<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <title>沉浸式视频播放器</title>
  <!-- 引入外部资源：Font Awesome 和 Inter 字体 -->
  <link href="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-0-y/font-awesome/6.0.0/css/all.min.css" rel="stylesheet" />
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
  <!-- HLS.js 和 FLV.js 库 -->
  <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-0-y/hls.js/8.0.0-beta.3/hls.js"></script>
  <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-0-y/flv.js/1.6.2/flv.js"></script>

  <style>
    /* 全局样式 */
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    :root {
      /* 基础颜色 */
      --primary-color: #6a8dff; /* 鲜艳的蓝色 */
      --primary-dark-color: #4a6ce7;
      --text-light: #e0e0e0; /* 亮模式下的文本颜色 */
      --text-dark: #333333; /* 暗模式下的文本颜色 */
      --bg-light: #f0f2f5; /* 亮模式背景色 */
      --bg-dark: #1a1a1a; /* 暗模式背景色 */
      --card-bg-light: rgba(255, 255, 255, 0.8); /* 亮模式卡片背景 (毛玻璃) */
      --card-bg-dark: rgba(30, 30, 30, 0.8); /* 暗模式卡片背景 (毛玻璃) */
      --border-light: rgba(0, 0, 0, 0.1);
      --border-dark: rgba(255, 255, 255, 0.1);
      --success-color: #28a745;
      --warning-color: #ffc107;
      --danger-color: #dc3545;

      /* 阴影 */
      --shadow-light: 0 8px 30px rgba(0, 0, 0, 0.1);
      --shadow-dark: 0 8px 30px rgba(0, 0, 0, 0.4);

      /* 间距 */
      --spacing-xs: 4px;
      --spacing-sm: 8px;
      --spacing-md: 16px;
      --spacing-lg: 24px;
      --spacing-xl: 32px;

      /* 字体大小 */
      --font-size-xs: 12px;
      --font-size-sm: 14px;
      --font-size-md: 16px;
      --font-size-lg: 18px;
      --font-size-xl: 24px;

      /* 动画 */
      --transition-duration: 0.3s;
      --transition-ease: cubic-bezier(0.4, 0, 0.2, 1); /* Material Design easing */

      /* 毛玻璃效果 */
      --blur-amount: 10px; /* 默认模糊度 */
    }

    body {
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif;
      color: var(--text-dark); /* 默认亮模式文本 */
      line-height: 1.6;
      display: block; /* 允许内容正常流动和滚动 */
      min-height: auto; /* 移除最小高度限制 */
      background-color: var(--bg-light); /* 默认亮模式背景 */
      position: relative;
      overflow-x: hidden; /* 防止水平滚动 */
      padding: var(--spacing-md); /* 增加 body 边距 */
      transition: background-color var(--transition-duration) var(--transition-ease);
    }

    /* 背景图片和模糊效果 */
    body::before {
      content: '';
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      /* 移除了默认的背景图片URL，现在完全由JS控制 */
      background-image: var(--player-bg-image);
      background-size: cover;
      background-position: center;
      filter: blur(var(--player-bg-blur, 5px)); /* 默认模糊度 */
      z-index: -1;
      transition: filter var(--transition-duration) var(--transition-ease);
    }

    /* 暗模式 */
    body.dark-mode {
      color: var(--text-light);
      background-color: var(--bg-dark);
    }

    /* 应用容器 */
    #app-container {
      width: 95%;
      max-width: 1400px;
      min-height: auto; /* 允许根据内容自适应高度 */
      margin: 0 auto; /* 水平居中 */
      background: var(--card-bg-light); /* 毛玻璃背景 */
      backdrop-filter: blur(var(--blur-amount));
      -webkit-backdrop-filter: blur(var(--blur-amount)); /* Safari */
      border-radius: 20px;
      box-shadow: var(--shadow-light);
      display: flex;
      flex-direction: column;
      overflow: hidden; /* 确保圆角效果 */
      position: relative;
      z-index: 1;
      transition: background var(--transition-duration) var(--transition-ease), box-shadow var(--transition-duration) var(--transition-ease), backdrop-filter var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode #app-container {
      background: var(--card-bg-dark);
      box-shadow: var(--shadow-dark);
    }

    /* 头部 - 保持固定在顶部 */
    .header {
      padding: var(--spacing-md) var(--spacing-lg);
      display: flex;
      justify-content: space-between;
      align-items: center;
      border-bottom: 1px solid var(--border-light);
      transition: border-color var(--transition-duration) var(--transition-ease);
      position: sticky; /* 使头部固定在顶部 */
      top: 0;
      z-index: 1001; /* 确保在面板之上 */
      background: var(--card-bg-light); /* 确保背景色，避免内容透过 */
      backdrop-filter: blur(var(--blur-amount)); /* 保持毛玻璃效果 */
      -webkit-backdrop-filter: blur(var(--blur-amount));
    }

    body.dark-mode .header {
      border-color: var(--border-dark);
      background: var(--card-bg-dark);
    }

    .logo {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      color: var(--primary-color);
    }

    .logo i {
      font-size: var(--font-size-xl);
    }

    .logo h1 {
      font-size: var(--font-size-lg);
      font-weight: 700;
    }

    .header-actions {
      display: flex;
      gap: var(--spacing-sm);
    }

    /* 按钮基础样式 */
    .btn {
      padding: 10px 18px;
      border: none;
      border-radius: 12px;
      font-size: var(--font-size-sm);
      font-weight: 500;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: var(--spacing-xs);
      transition: all var(--transition-duration) var(--transition-ease);
      white-space: nowrap;
    }

    .btn-icon {
      width: 40px;
      height: 40px;
      padding: 0;
      border-radius: 50%;
    }

    .btn-primary {
      background: var(--primary-color);
      color: white;
    }

    .btn-primary:hover {
      background: var(--primary-dark-color);
      transform: translateY(-2px);
      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    }

    .btn-secondary {
      background: rgba(0, 0, 0, 0.05);
      color: var(--text-dark);
      border: 1px solid var(--border-light);
    }

    body.dark-mode .btn-secondary {
      background: rgba(255, 255, 255, 0.05);
      color: var(--text-light);
      border-color: var(--border-dark);
    }

    .btn-secondary:hover {
      background: rgba(0, 0, 0, 0.1);
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }

    body.dark-mode .btn-secondary:hover {
      background: rgba(255, 255, 255, 0.1);
    }

    .btn-danger {
      background: var(--danger-color);
      color: white;
    }

    .btn-danger:hover {
      background: #c82333;
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }

    .btn-success {
      background: var(--success-color);
      color: white;
    }

    .btn-success:hover {
      background: #218838;
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }

    .btn.active-speed-btn,
    .btn.active-preset,
    .btn.active-loop-mode { /* 新增 active-loop-mode */
      background-color: var(--primary-dark-color);
      color: white;
      border-color: var(--primary-dark-color);
    }

    /* 主内容区 */
    .main-content {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      padding: var(--spacing-lg);
      gap: var(--spacing-lg);
      position: relative;
    }

    /* 视频播放器区域 */
    .video-player-section {
      flex-grow: 1;
      position: relative;
      border-radius: 15px;
      overflow: hidden;
      background-color: #000; /* 视频背景 */
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 300px; /* 确保有最小高度 */
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
    }

    .video-container {
      position: relative;
      width: 100%;
      padding-top: 56.25%; /* 16:9 宽高比 */
      background: #000;
      display: none; /* 默认隐藏 */
      overflow: hidden;
    }

    .video-container.visible {
      display: block;
    }

    .video-container.fullscreen-active {
      padding-top: 0 !important;
      width: 100vw;
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 0;
      position: fixed; /* 全屏时固定定位 */
      top: 0;
      left: 0;
      z-index: 9999; /* 确保在最顶层 */
    }

    #videoPlayer {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      outline: none;
      object-fit: contain;
      transition: transform 0.1s ease-out, filter 0.1s ease-out;
    }

    .video-container.fullscreen-active #videoPlayer {
      position: static;
      width: 100%;
      height: 100%;
      object-fit: contain;
    }

    /* 视频内部控制条 */
    #inVideoControls {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      padding: var(--spacing-sm) var(--spacing-md);
      background: linear-gradient(to top, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0)); /* 渐变背景 */
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      opacity: 0; /* Default hidden */
      pointer-events: none; /* Default no interaction */
      transition: opacity var(--transition-duration) var(--transition-ease);
      z-index: 10; /* 确保在视频上方 */
    }

    #inVideoControls.controls-visible {
      opacity: 1;
      pointer-events: auto;
    }

    #inVideoControls .btn-icon {
      background: rgba(255, 255, 255, 0.2);
      color: white;
      border: none;
      width: 36px;
      height: 36px;
      font-size: var(--font-size-md);
    }

    #inVideoControls .btn-icon:hover {
      background: rgba(255, 255, 255, 0.4);
      transform: none; /* 移除悬停动画 */
      box-shadow: none;
    }

    #inVideoControls .time-display {
      color: white;
      font-size: var(--font-size-sm);
      min-width: 45px;
      text-align: center;
      text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    }

    #inVideoControls .seek-slider {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(255, 255, 255, 0.3);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    #inVideoControls .seek-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
    }

    #inVideoControls .volume-controls {
      display: flex;
      align-items: center;
      gap: var(--spacing-xs);
      color: white;
    }

    #inVideoControls .volume-controls i {
      font-size: var(--font-size-md);
      cursor: pointer;
      text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    }

    #inVideoControls .volume-slider {
      width: 80px;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(255, 255, 255, 0.3);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    #inVideoControls .volume-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 14px;
      height: 14px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
    }

    #inVideoControls #inVideoVolumePercentageDisplay {
      font-size: var(--font-size-sm);
      min-width: 35px;
      text-align: right;
      text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    }

    /* 上传占位符 */
    .upload-placeholder {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      text-align: center;
      background: var(--card-bg-light); /* 毛玻璃背景 */
      backdrop-filter: blur(var(--blur-amount)); /* 毛玻璃效果 */
      -webkit-backdrop-filter: blur(var(--blur-amount)); /* Safari */
      border: 2px dashed var(--border-light); /* 虚线边框 */
      border-radius: 15px;
      cursor: pointer;
      transition: all var(--transition-duration) var(--transition-ease);
      padding: var(--spacing-lg);
      z-index: 1;
      color: var(--text-dark); /* 文本颜色 */
    }

    body.dark-mode .upload-placeholder {
      background: var(--card-bg-dark);
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    .upload-placeholder.drag-over {
      border-color: var(--primary-color);
      background: rgba(106, 141, 255, 0.1); /* 拖拽时的背景 */
    }

    body.dark-mode .upload-placeholder.drag-over {
      background: rgba(106, 141, 255, 0.2);
    }

    .upload-placeholder.hidden {
      display: none;
    }

    .upload-placeholder i {
      font-size: 64px;
      color: var(--primary-color);
      margin-bottom: var(--spacing-md);
    }

    .upload-placeholder h3 {
      font-size: var(--font-size-lg);
      margin-bottom: var(--spacing-sm);
    }

    .upload-placeholder p {
      font-size: var(--font-size-sm);
      opacity: 0.8;
    }

    /* 主控制条 (在视频下方) */
    .main-control-bar {
      padding: var(--spacing-md) var(--spacing-lg);
      display: flex;
      flex-direction: column;
      gap: var(--spacing-md);
      border-top: 1px solid var(--border-light);
      transition: border-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .main-control-bar {
      border-color: var(--border-dark);
    }

    /* 播放器顶部控制行 (包含播放/暂停、进度条、音量、全屏) */
    #topPlayerControls {
      display: flex;
      align-items: center;
      gap: var(--spacing-md);
      flex-wrap: wrap; /* 允许换行 */
    }

    #topPlayerControls .btn-icon {
      flex-shrink: 0; /* 防止按钮被压缩 */
    }

    /* 进度条容器 */
    .progress-bar-container {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      flex-grow: 1; /* 占据剩余空间 */
    }

    .seek-slider {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.3); /* 进度条背景 */
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    body.dark-mode .seek-slider {
      background: rgba(255, 255, 255, 0.3);
    }

    .seek-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 18px;
      height: 18px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }

    .seek-slider::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    .time-display {
      font-size: var(--font-size-sm);
      color: var(--text-dark); /* 亮模式文本 */
      min-width: 50px;
      text-align: center;
      font-variant-numeric: tabular-nums; /* 确保数字宽度一致 */
    }

    body.dark-mode .time-display {
      color: var(--text-light);
    }

    /* 音量控制 */
    .volume-controls {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      color: var(--text-dark); /* 亮模式文本 */
      flex-shrink: 0; /* 防止被压缩 */
    }

    body.dark-mode .volume-controls {
      color: var(--text-light);
    }

    .volume-controls i {
      font-size: var(--font-size-lg);
      cursor: pointer;
    }

    .volume-slider {
      width: 80px; /* 较短的音量条 */
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.3);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
    }

    body.dark-mode .volume-slider {
      background: rgba(255, 255, 255, 0.3);
    }

    .volume-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }

    .volume-slider::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    /* 音量百分比显示 */
    #volumePercentageDisplay {
      font-size: var(--font-size-sm);
      min-width: 35px; /* 确保宽度足够显示三位数 */
      text-align: right;
    }

    .control-row {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: wrap;
    }

    .input-group {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: wrap;
      flex-grow: 1;
    }

    .input-group input[type="text"] {
      flex: 1;
      min-width: 200px;
      padding: 12px 16px;
      border: 1px solid var(--border-light);
      border-radius: 12px;
      font-size: var(--font-size-sm);
      background: transparent;
      color: var(--text-dark);
      transition: all var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .input-group input[type="text"] {
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    .input-group input[type="text"]:focus {
      border-color: var(--primary-color);
      outline: none;
      box-shadow: 0 0 0 3px rgba(106, 141, 255, 0.2);
    }

    .file-input-wrapper {
      position: relative;
      overflow: hidden;
      display: inline-block;
    }

    .file-input-wrapper input[type=file] {
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0;
      width: 100%;
      height: 100%;
      cursor: pointer;
    }

    .btn-group {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: wrap;
    }

    /* 状态指示器 */
    .status-indicator {
      padding: 8px 16px;
      border-radius: 20px;
      font-size: var(--font-size-sm);
      font-weight: 500;
      display: inline-flex;
      align-items: center;
      gap: 6px;
      margin-top: var(--spacing-sm);
      align-self: flex-start; /* 左对齐 */
    }

    .status-indicator.playing {
      background: rgba(40, 167, 69, 0.15);
      color: var(--success-color);
    }

    .status-indicator.stopped {
      background: rgba(220, 53, 69, 0.15);
      color: var(--danger-color);
    }

    .status-indicator.loading {
      background: rgba(255, 193, 7, 0.15);
      color: var(--warning-color);
    }

    .status-indicator i {
      animation: pulse 1.5s infinite;
    }

    @keyframes pulse {
      0% {
        opacity: 1;
      }

      50% {
        opacity: 0.5;
      }

      100% {
        opacity: 1;
      }
    }

    /* 字幕显示 */
    .subtitle-display {
      position: absolute;
      bottom: 80px; /* 调整位置，避免与控制条重叠 */
      left: 50%;
      transform: translateX(-50%);
      width: auto;
      max-width: 90%;
      padding: 8px 12px;
      color: white;
      font-size: 20px;
      font-weight: 500;
      z-index: 10;
      border-radius: 6px;
      text-align: center;
      line-height: 1.4;
      pointer-events: none;
      display: none;
      text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.9);
      background-color: transparent;
      transition: all var(--transition-duration) var(--transition-ease);
    }

    /* 全屏模式下的字幕显示 */
    .video-container.fullscreen-active .subtitle-display {
      position: fixed;
      bottom: 80px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 2147483647;
      max-width: 90%;
      width: auto;
    }

    /* 浮动面板（设置和历史） */
    .drawer-panel {
      position: fixed;
      top: 0; /* 初始顶部位置，会被 JS 动态调整 */
      width: 320px;
      height: auto; /* 高度自适应内容 */
      max-height: calc(100vh - 2 * var(--spacing-md)); /* 限制最大高度 */
      overflow-y: auto; /* 内容溢出时滚动 */
      background: var(--card-bg-light);
      backdrop-filter: blur(var(--blur-amount));
      -webkit-backdrop-filter: blur(var(--blur-amount));
      border-radius: 20px;
      box-shadow: var(--shadow-light);
      z-index: 1000; /* 比头部低一点 */
      transition: transform var(--transition-duration) var(--transition-ease), background var(--transition-duration) var(--transition-ease), box-shadow var(--transition-duration) var(--transition-ease), backdrop-filter var(--transition-duration) var(--transition-ease);
      display: flex;
      flex-direction: column; /* 垂直堆叠内容 */
      padding: var(--spacing-md); /* 面板内边距 */
    }

    body.dark-mode .drawer-panel {
      background: var(--card-bg-dark);
      box-shadow: var(--shadow-dark);
    }

    /* 默认隐藏状态 */
    .settings-panel-drawer {
      right: var(--spacing-md);
      transform: translateX(calc(100% + var(--spacing-md))); /* 默认隐藏在右侧 */
    }

    .history-panel-drawer {
      left: var(--spacing-md);
      transform: translateX(calc(-100% - var(--spacing-md))); /* 默认隐藏在左侧 */
    }

    /* 打开状态 */
    .settings-panel-drawer.open,
    .history-panel-drawer.open {
      transform: translateX(0); /* 显示面板 */
    }

    .drawer-header {
      padding: 0 0 var(--spacing-md) 0; /* 调整内边距，移除左右，只留底部 */
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: var(--font-size-lg);
      font-weight: 600;
      border-bottom: 1px solid var(--border-light);
      color: var(--primary-color);
      transition: border-color var(--transition-duration) var(--transition-ease);
      margin-bottom: var(--spacing-md); /* 标题和内容间距 */
    }

    body.dark-mode .drawer-header {
      border-color: var(--border-dark);
    }

    /* 抽屉面板标题的通用样式 */
    .drawer-header .drawer-title-wrapper {
        display: flex;
        align-items: center;
        gap: var(--spacing-sm); /* 图标和文字之间的间距 */
    }

    /* 历史面板标题的特定样式：文字左对齐 */
    #historyPanel .drawer-header .history-title-text {
        flex-grow: 0; /* 不占据额外空间 */
        text-align: left; /* 文本左对齐 */
    }
    /* 确保历史面板标题的图标和文字组在左侧 */
    #historyPanel .drawer-header {
        justify-content: space-between; /* 保持图标/文字组和关闭按钮两端对齐 */
    }


    .drawer-header .close-btn {
      background: none;
      border: none;
      font-size: var(--font-size-xl);
      color: var(--text-dark);
      cursor: pointer;
      transition: all var(--transition-duration) var(--transition-ease); /* 统一过渡效果 */
      /* 新增样式 */
      width: 36px; /* 按钮宽度 */
      height: 36px; /* 按钮高度 */
      border-radius: 8px; /* 圆角矩形 */
      padding: 0; /* 移除内边距，让图标居中 */
      display: flex; /* 使用 flex 居中图标 */
      align-items: center;
      justify-content: center;
      background: rgba(0, 0, 0, 0.05); /* 默认背景色 */
    }

    body.dark-mode .drawer-header .close-btn {
      color: var(--text-light);
      background: rgba(255, 255, 255, 0.05); /* 暗模式背景色 */
    }

    .drawer-header .close-btn:hover {
      background: rgba(0, 0, 0, 0.1); /* 悬停背景色 */
      transform: translateY(-1px);
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 悬停阴影 */
      color: var(--primary-color); /* 悬停时改变颜色 */
    }
    body.dark-mode .drawer-header .close-btn:hover {
      background: rgba(255, 255, 255, 0.1);
    }

    .drawer-content {
      flex-grow: 1;
      padding: 0; /* 移除 drawer-content 额外内边距 */
      overflow-y: auto; /* 允许内容滚动 */
    }

    .setting-group {
      margin-bottom: var(--spacing-lg);
      padding-bottom: var(--spacing-md);
      border-bottom: 1px solid var(--border-light);
      transition: border-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group {
      border-color: var(--border-dark);
    }

    .setting-group:last-child {
      border-bottom: none;
      margin-bottom: 0;
      padding-bottom: 0;
    }

    .setting-group h4 {
      font-size: var(--font-size-md);
      margin-bottom: var(--spacing-md);
      color: var(--text-dark);
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group h4 {
      color: var(--text-light);
    }

    .slider-group {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
      margin-bottom: var(--spacing-sm);
    }

    .slider-group label {
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      white-space: nowrap;
      min-width: 60px;
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .slider-group label {
      color: var(--text-light);
    }

    .slider-group input[type="range"] {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.1);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
      transition: background var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .slider-group input[type="range"] {
      background: rgba(255, 255, 255, 0.1);
    }

    .slider-group input[type="range"]::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }

    .slider-group input[type="range"]::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    .slider-group span {
      font-size: var(--font-size-sm);
      min-width: 40px;
      text-align: right;
      color: var(--text-dark);
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .slider-group span {
      color: var(--text-light);
    }

    .setting-group input[type="color"] {
      width: 40px;
      height: 40px;
      border: 1px solid var(--border-light);
      padding: 0;
      background: none;
      cursor: pointer;
      border-radius: 8px;
      overflow: hidden;
      transition: border-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group input[type="color"] {
      border-color: var(--border-dark);
    }

    .setting-group input[type="color"]::-webkit-color-swatch-wrapper {
      padding: 0;
    }
    .setting-group input[type="color"]::-webkit-color-swatch {
      border: none;
      border-radius: 8px;
    }

    .setting-group input[type="number"] {
      width: 60px;
      padding: 8px;
      border: 1px solid var(--border-light);
      border-radius: 8px;
      font-size: var(--font-size-sm);
      background: transparent;
      color: var(--text-dark);
      text-align: center;
      transition: all var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .setting-group input[type="number"] {
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    /* 历史记录列表 */
    .history-list {
      padding-top: var(--spacing-sm);
    }

    .history-item {
      padding: var(--spacing-sm) 0;
      border-bottom: 1px solid var(--border-light);
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: var(--spacing-sm);
      cursor: pointer;
      transition: background-color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .history-item {
      border-color: var(--border-dark);
    }

    .history-item:hover {
      background-color: rgba(106, 141, 255, 0.05); /* primary-color 的淡化 */
    }

    .history-item:last-child {
      border-bottom: none;
    }

    .history-item .title-wrapper {
      flex: 1;
      min-width: 150px;
      display: flex;
      align-items: center;
      gap: var(--spacing-xs);
    }

    .history-item .history-title-display {
      flex: 1;
      word-break: break-word;
      line-height: 1.4;
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .history-item .history-title-display {
      color: var(--text-light);
    }

    .history-item .history-title-edit {
      flex: 1;
      padding: 6px 10px;
      border: 1px solid var(--border-light);
      border-radius: 8px;
      font-size: var(--font-size-sm);
      background: transparent;
      color: var(--text-dark);
      min-width: 100px;
      word-break: break-word;
      line-height: 1.4;
      height: auto;
      resize: vertical;
      transition: all var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .history-item .history-title-edit {
      border-color: var(--border-dark);
      color: var(--text-light);
    }

    .history-item .actions {
      display: flex;
      gap: var(--spacing-xs);
      margin-left: auto;
      flex-shrink: 0;
    }

    .history-item .actions button {
      background: none;
      border: none;
      color: var(--text-dark);
      cursor: pointer;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      border-radius: 8px;
      transition: all var(--transition-duration) var(--transition-ease);
      padding: 6px;
      min-width: 45px;
    }

    body.dark-mode .history-item .actions button {
      color: var(--text-light);
    }

    .history-item .actions button:hover {
      background: rgba(106, 141, 255, 0.1);
      color: var(--primary-color);
    }

    .history-item .actions .button-label {
      font-size: 10px;
      color: inherit; /* 继承父元素颜色 */
      white-space: nowrap;
      opacity: 0.8;
    }

    .empty-history {
      padding: var(--spacing-xl) var(--spacing-md);
      text-align: center;
      color: var(--text-dark);
      opacity: 0.7;
      transition: color var(--transition-duration) var(--transition-ease);
    }

    body.dark-mode .empty-history {
      color: var(--text-light);
    }

    .format-tag {
      display: inline-block;
      padding: 4px 8px;
      border-radius: 6px;
      background: rgba(106, 141, 255, 0.1);
      color: var(--primary-color);
      font-size: var(--font-size-xs);
      font-weight: 500;
      white-space: nowrap;
      flex-shrink: 0; /* 防止被压缩 */
    }

    /* 字幕控制组 */
    .subtitle-controls-group {
      display: flex;
      flex-wrap: wrap;
      gap: var(--spacing-sm); /* 保持按钮之间的间距 */
      align-items: center;
      flex-grow: 1; /* 占据可用空间 */
    }

    /* 字幕大小和颜色调节的容器 */
    .subtitle-size-color-controls {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm); /* 内部元素间距 */
      flex-wrap: wrap;
      flex-grow: 1; /* 占据剩余空间 */
      min-width: 280px; /* 确保在小屏幕上有足够的空间 */
    }

    .subtitle-size-color-controls .subtitle-label {
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      white-space: nowrap;
      transition: color var(--transition-duration) var(--transition-ease);
    }
    body.dark-mode .subtitle-size-color-controls .subtitle-label {
      color: var(--text-light);
    }

    .subtitle-size-color-controls .subtitle-range-slider {
      flex: 1;
      height: 6px;
      -webkit-appearance: none;
      background: rgba(0, 0, 0, 0.1);
      border-radius: 3px;
      outline: none;
      cursor: pointer;
      transition: background var(--transition-duration) var(--transition-ease);
      min-width: 80px; /* 确保滑块有最小宽度 */
    }
    body.dark-mode .subtitle-size-color-controls .subtitle-range-slider {
      background: rgba(255, 255, 255, 0.1);
    }
    .subtitle-size-color-controls .subtitle-range-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--primary-color);
      cursor: pointer;
      transition: transform var(--transition-duration) var(--transition-ease);
    }
    .subtitle-size-color-controls .subtitle-range-slider::-webkit-slider-thumb:hover {
      transform: scale(1.1);
    }

    /* 数值输入框和单位的包裹器 */
    .input-with-unit {
      display: flex;
      align-items: center;
      gap: var(--spacing-xs); /* input 和 px 之间的间距 */
    }

    /* 数值输入框样式，使其看起来像按钮 */
    .custom-input-number {
      padding: 6px 10px; /* Adjusted padding */
      border: 1px solid var(--border-light);
      border-radius: 8px; /* Slightly smaller border-radius for inputs */
      font-size: var(--font-size-sm);
      background: rgba(0, 0, 0, 0.05); /* Match btn-secondary background */
      color: var(--text-dark);
      text-align: center;
      transition: all var(--transition-duration) var(--transition-ease);
      width: 55px; /* Fixed width for the number input */
      -webkit-appearance: none; /* Remove default spinner buttons */
      -moz-appearance: textfield; /* Firefox */
      appearance: textfield; /* Standard */
    }
    body.dark-mode .custom-input-number {
      border-color: var(--border-dark);
      background: rgba(255, 255, 255, 0.05);
      color: var(--text-light);
    }
    .custom-input-number:focus {
      border-color: var(--primary-color);
      outline: none;
      box-shadow: 0 0 0 3px rgba(106, 141, 255, 0.2);
    }
    /* 重新添加数值输入框的上下调节按钮 */
    .custom-input-number::-webkit-inner-spin-button,
    .custom-input-number::-webkit-outer-spin-button {
      -webkit-appearance: spinner-buttons;
      opacity: 1; /* Make them visible */
      cursor: pointer;
      height: auto; /* Adjust height */
      width: 16px; /* Adjust width */
      margin: 0; /* Remove default margin */
      padding: 0; /* Remove default padding */
      background: transparent;
      border: none;
      color: var(--text-dark); /* Color of the arrows */
    }
    body.dark-mode .custom-input-number::-webkit-inner-spin-button,
    body.dark-mode .custom-input-number::-webkit-outer-spin-button {
        color: var(--text-light);
    }

    /* 单位文字样式 */
    .unit-text {
      font-size: var(--font-size-sm);
      color: var(--text-dark);
      white-space: nowrap;
      transition: color var(--transition-duration) var(--transition-ease);
    }
    body.dark-mode .unit-text {
      color: var(--text-light);
    }

    /* 颜色选择器样式，使其看起来像按钮 */
    .custom-input-color {
      width: 40px; /* Fixed width */
      height: 40px; /* Fixed height */
      min-width: 40px; /* Ensure it doesn't shrink */
      padding: 0; /* No padding inside for color picker */
      border: 1px solid var(--border-light);
      border-radius: 8px; /* Match number input border-radius */
      background: rgba(0, 0, 0, 0.05); /* Match btn-secondary background */
      cursor: pointer;
      overflow: hidden; /* Hide default color picker border */
      transition: all var(--transition-duration) var(--transition-ease);
      -webkit-appearance: none; /* Remove default styles */
      appearance: none; /* Remove default styles */
    }
    body.dark-mode .custom-input-color {
      border-color: var(--border-dark);
      background: rgba(255, 255, 255, 0.05);
    }
    .custom-input-color::-webkit-color-swatch-wrapper {
      padding: 0;
    }
    .custom-input-color::-webkit-color-swatch {
      border: none;
      border-radius: 8px; /* Match outer border-radius */
    }
    .custom-input-color:hover {
      background: rgba(0, 0, 0, 0.1);
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
    }
    body.dark-mode .custom-input-color:hover {
      background: rgba(255, 255, 255, 0.1);
    }

    /* 全宽按钮 */
    .btn-full-width {
        width: 100%;
    }
    /* 修复重置滤镜按钮与预设按钮重叠 */
    #resetFilterBtn {
        margin-top: var(--spacing-md); /* 增加顶部外边距 */
    }

    /* 画面调节按钮并排优化 */
    .setting-group .btn-group {
        flex-wrap: nowrap; /* 强制不换行 */
        overflow-x: auto; /* 如果内容溢出，允许水平滚动 */
        justify-content: space-between; /* 按钮之间均匀分布 */
    }
    .setting-group .btn-group .btn {
        flex: 1 1 0; /* 均匀分配空间 */
        min-width: unset; /* 取消最小宽度限制 */
        padding: 8px 12px; /* 调整内边距 */
        font-size: var(--font-size-xs); /* 调整字体大小 */
    }

    /* 历史记录循环模式按钮组 */
    .history-loop-controls {
      display: flex;
      gap: var(--spacing-sm);
      flex-wrap: nowrap; /* 强制不换行 */
      overflow-x: auto; /* 允许水平滚动 */
      justify-content: flex-end; /* 按钮靠右对齐 */
      padding-bottom: var(--spacing-sm); /* 底部留白，防止滚动条遮挡 */
      -webkit-overflow-scrolling: touch; /* 移动端平滑滚动 */
    }
    .history-loop-controls .btn {
      flex-shrink: 0; /* 防止按钮被压缩 */
      padding: 8px 12px; /* 调整按钮内边距 */
      font-size: var(--font-size-xs); /* 调整字体大小 */
    }


    /* 响应式设计 */
    @media (max-width: 1024px) {
      #app-container {
        width: 98%;
        min-height: auto;
        border-radius: 15px;
      }

      .main-content {
        padding: var(--spacing-md);
        gap: var(--spacing-md);
      }

      .header {
        padding: var(--spacing-sm) var(--spacing-md);
      }

      .logo h1 {
        font-size: var(--font-size-md);
      }

      .btn {
        padding: 8px 14px;
        font-size: var(--font-size-xs);
      }

      .btn-icon {
        width: 36px;
        height: 36px;
        font-size: var(--font-size-md);
      }

      .upload-placeholder i {
        font-size: 50px;
      }

      .upload-placeholder h3 {
        font-size: var(--font-size-md);
      }

      .upload-placeholder p {
        font-size: var(--font-size-xs);
      }

      #topPlayerControls {
        padding: 0; /* 移除额外内边距 */
      }

      .time-display {
        font-size: var(--font-size-xs);
        min-width: 45px;
      }

      .volume-slider {
        width: 60px;
      }

      .main-control-bar {
        padding: var(--spacing-sm) var(--spacing-md);
        gap: var(--spacing-sm);
      }

      .input-group input[type="text"] {
        padding: 10px 14px;
        font-size: var(--font-size-xs);
      }

      .status-indicator {
        font-size: var(--font-size-xs);
        padding: 6px 12px;
      }

      .drawer-panel {
        width: 280px;
        padding: var(--spacing-sm); /* 调整面板内边距 */
      }

      .drawer-header {
        font-size: var(--font-size-md);
        padding: 0 0 var(--spacing-sm) 0; /* 调整头部内边距 */
        margin-bottom: var(--spacing-sm);
      }

      .drawer-header .close-btn {
        font-size: var(--font-size-lg);
      }

      .drawer-content {
        padding: 0; /* 移除额外内边距 */
      }

      .setting-group h4 {
        font-size: var(--font-size-sm);
      }

      .slider-group label,
      .slider-group span,
      .setting-group input[type="number"] {
        font-size: var(--font-size-xs);
      }

      .history-item .history-title-display,
      .history-item .history-title-edit {
        font-size: var(--font-size-xs);
      }

      .history-item .actions button {
        min-width: 40px;
        padding: 4px;
      }

      .history-item .actions button i {
        font-size: var(--font-size-sm);
      }

      /* 字幕控制组在平板上 */
      .subtitle-size-color-controls {
        flex-basis: auto; /* 自动调整宽度 */
        flex-grow: 1;
      }
    }

    @media (max-width: 768px) {
      body {
        padding: var(--spacing-sm);
      }

      #app-container {
        width: 100%;
        min-height: auto;
        border-radius: 0; /* 移动端全屏 */
        box-shadow: none;
      }

      .header {
        padding: var(--spacing-xs) var(--spacing-sm);
      }

      .logo h1 {
        display: none; /* 移动端隐藏标题，只显示图标 */
      }

      .header-actions {
        gap: var(--spacing-xs);
      }

      .header-actions #headerHistoryToggleBtn,
      .header-actions #headerSettingsToggleBtn {
        display: flex; /* 确保它们在头部可见 */
      }

      .btn {
        padding: 6px 10px;
        font-size: var(--font-size-xs);
      }

      .btn-icon {
        width: 32px;
        height: 32px;
        font-size: var(--font-size-sm);
      }

      .main-content {
        padding: var(--spacing-sm);
        gap: var(--spacing-sm);
      }

      /* 统一控制行布局 */
      .control-row {
        flex-direction: column; /* 默认堆叠 */
        align-items: flex-start;
        gap: var(--spacing-sm); /* 统一间距 */
      }

      /* 特殊处理播放器顶部控制行，保持一行 */
      #topPlayerControls {
        flex-direction: row;
        justify-content: space-between;
        width: 100%;
        gap: var(--spacing-xs); /* 缩小间距 */
      }
      #topPlayerControls .btn-icon {
        width: 36px; /* 稍微大一点，方便点击 */
        height: 36px;
      }
      #topPlayerControls .time-display {
        min-width: 40px; /* 确保时间显示完整 */
      }
      #topPlayerControls .volume-slider {
        width: 50px; /* 进一步缩小音量条 */
      }
      #topPlayerControls #volumePercentageDisplay {
        min-width: 30px; /* 适应更小的音量百分比显示 */
      }

      /* 视频内部控制条在移动端始终显示 */
      #inVideoControls {
        background: rgba(0, 0, 0, 0.8); /* 移动端背景更实 */
        padding: var(--spacing-xs); /* 最小化内边距 */
        gap: var(--spacing-xs); /* 最小化元素间距 */
        flex-wrap: nowrap; /* 强制不换行 */
        overflow-x: hidden; /* 确保没有水平滚动条 */
        justify-content: space-between; /* 均匀分布 */
      }
      #inVideoControls .btn-icon {
        width: 32px;
        height: 32px;
        font-size: var(--font-size-sm);
        flex-shrink: 0;
      }
      #inVideoControls .time-display {
        font-size: 10px; /* 进一步缩小字体 */
        min-width: 30px; /* 确保有最小宽度 */
        flex-shrink: 0;
      }
      #inVideoControls .seek-slider {
        flex-grow: 1;
        min-width: 40px; /* 确保有最小宽度 */
      }
      #inVideoControls .volume-controls {
        flex-shrink: 0;
        gap: 2px; /* 缩小音量控制内部间距 */
      }
      #inVideoControls .volume-controls i {
          font-size: 14px; /* 缩小音量图标 */
      }
      #inVideoControls .volume-slider {
        width: 30px; /* 进一步缩小 */
      }
      #inVideoControls #inVideoVolumePercentageDisplay {
        font-size: 10px; /* 进一步缩小字体 */
        min-width: 20px;
      }


      /* 输入组和文件上传按钮 */
      .input-group,
      .file-input-wrapper {
        width: 100%; /* 占据整行 */
      }
      .input-group input[type="text"],
      .input-group .btn,
      .file-input-wrapper .btn {
        width: 100%; /* 内部元素也占据整行 */
        min-width: unset;
      }

      /* 按钮组 */
      .btn-group {
        width: 100%;
        justify-content: space-between; /* 按钮之间均匀分布 */
        gap: var(--spacing-xs); /* 缩小按钮组内部间距 */
      }
      .btn-group .btn {
        flex: 1 1 auto; /* 自动分配宽度 */
        min-width: unset;
        padding: 8px 10px; /* 调整按钮内边距 */
        font-size: var(--font-size-xs); /* 调整字体大小 */
      }

      /* 字幕控制组在手机上 */
      .subtitle-controls-group {
        flex-direction: column; /* 堆叠排列 */
        align-items: flex-start;
        width: 100%;
      }
      .subtitle-controls-group .btn {
        width: 100%; /* 按钮占据整行 */
      }
      .subtitle-size-color-controls {
        flex-direction: row; /* 保持在同一行 */
        flex-wrap: wrap;
        width: 100%;
        justify-content: flex-start; /* 左对齐 */
        gap: var(--spacing-sm); /* 保持内部间距 */
      }
      .subtitle-size-color-controls .subtitle-label {
        flex-basis: auto; /* 允许标签自适应 */
        min-width: unset;
      }
      .subtitle-size-color-controls .subtitle-range-slider {
        flex-grow: 1; /* 滑块占据可用空间 */
        min-width: 60px; /* 调整最小宽度 */
      }
      .input-with-unit {
        flex-shrink: 0; /* 防止收缩 */
      }
      .custom-input-number {
        width: 50px; /* 调整宽度 */
        padding: 4px 8px; /* 调整内边距 */
      }
      .custom-input-color {
        width: 36px; /* 调整大小 */
        height: 36px;
        min-width: 36px;
      }

      .history-item .actions {
        width: 100%;
        justify-content: flex-start;
      }

      /* 历史记录循环模式按钮组在移动端 */
      .history-loop-controls {
        justify-content: space-between; /* 均匀分布 */
        gap: var(--spacing-xs); /* 缩小间距 */
      }
      .history-loop-controls .btn {
        flex: 1 1 auto; /* 自动分配宽度 */
        min-width: unset;
        font-size: var(--font-size-xs);
        padding: 6px 8px;
      }
    }
  </style>
</head>
<body>
  <div id="app-container">
    <header class="header">
      <div class="logo">
        <i class="fas fa-play-circle"></i>
        <h1>沉浸式视频播放器</h1>
      </div>
      <div class="header-actions">
        <button class="btn btn-icon btn-secondary" id="themeToggle" aria-label="切换主题">
          <i class="fas fa-moon"></i>
        </button>
        <!-- 头部历史记录按钮 (桌面/移动端都可见) -->
        <button class="btn btn-icon btn-secondary" id="headerHistoryToggleBtn" aria-label="打开历史记录">
          <i class="fas fa-history"></i>
        </button>
        <!-- 头部设置按钮 (桌面/移动端都可见) -->
        <button class="btn btn-icon btn-secondary" id="headerSettingsToggleBtn" aria-label="打开设置">
          <i class="fas fa-cog"></i>
        </button>
      </div>
    </header>

    <main class="main-content">
      <section class="video-player-section">
        <!-- 上传占位符，默认显示 -->
        <div id="uploadPlaceholder" class="upload-placeholder">
          <i class="fas fa-cloud-upload-alt"></i>
          <h3>拖放视频文件到此处</h3>
          <p>或点击选择本地视频 / 输入在线 URL</p>
          <p class="text-small">支持 MP4, M3U8, FLV, WebM, MKV 等主流格式</p>
        </div>

        <!-- 视频播放器容器，默认隐藏 -->
        <div class="video-container" id="videoContainer">
          <video id="videoPlayer" crossorigin="anonymous"></video> <!-- 移除 controls 属性 -->
          <div id="subtitleDisplay" class="subtitle-display" style="display: none;"></div>

          <!-- 视频内部控制条 -->
          <div id="inVideoControls">
            <button class="btn btn-icon" id="inVideoPlayPauseBtn" aria-label="播放/暂停">
              <i class="fas fa-play"></i>
            </button>
            <div id="inVideoCurrentTimeDisplay" class="time-display">00:00</div>
            <input type="range" min="0" max="0" value="0" step="0.01" class="seek-slider" id="inVideoSeekSlider" aria-label="播放进度">
            <div id="inVideoDurationDisplay" class="time-display">00:00</div>
            <div class="volume-controls">
              <i class="fas fa-volume-up" id="inVideoVolumeIcon" aria-label="音量图标"></i>
              <input type="range" min="0" max="100" value="100" class="volume-slider" id="inVideoVolumeSlider" aria-label="音量调节">
              <span id="inVideoVolumePercentageDisplay">100%</span>
            </div>
            <button class="btn btn-icon" id="inVideoFullscreenBtn" aria-label="全屏">
              <i class="fas fa-expand"></i>
            </button>
          </div>
        </div>
      </section>

      <!-- 主控制条 (在视频下方，包含 URL 输入、上传、速度等) -->
      <section class="main-control-bar">
        <!-- 播放器顶部控制行 (包含播放/暂停、进度条、音量、全屏) -->
        <div class="control-row" id="topPlayerControls">
          <button class="btn btn-icon btn-secondary" id="playPauseBtn" aria-label="播放/暂停">
            <i class="fas fa-play"></i>
          </button>
          <div class="progress-bar-container">
            <div id="currentTimeDisplay" class="time-display">00:00</div>
            <input type="range" min="0" max="0" value="0" step="0.01" class="seek-slider" id="seekSlider" aria-label="播放进度">
            <div id="durationDisplay" class="time-display">00:00</div>
          </div>
          <div class="volume-controls">
            <i class="fas fa-volume-up" id="volumeIcon" aria-label="音量图标"></i>
            <input type="range" min="0" max="100" value="100" class="volume-slider" id="volumeSlider" aria-label="音量调节">
            <span id="volumePercentageDisplay">100%</span> <!-- 音量百分比显示 -->
            <button class="btn btn-icon btn-secondary" id="muteButton" aria-label="静音/取消静音">
              <i class="fas fa-volume-up" id="muteButtonIcon"></i>
            </button>
            <button class="btn btn-icon btn-secondary" onclick="toggleFullscreen()" aria-label="全屏">
              <i class="fas fa-expand"></i>
            </button>
          </div>
        </div>

        <div class="control-row">
          <div class="input-group">
            <input
              type="text"
              id="videoURL"
              placeholder="输入视频URL (支持所有主流视频格式)"
              value="http://cloud.ruiboyun.net/vod/vod3/e0u83v08/index.m3u8"
              aria-label="视频URL输入框"
            />
            <button class="btn btn-primary" id="loadVideoBtn">
              <i class="fas fa-play"></i> 加载视频
            </button>
            <button class="btn btn-secondary" id="reloadVideoBtn">
              <i class="fas fa-sync-alt"></i> 重新加载
            </button>
            <button class="btn btn-danger" onclick="stopPlayback()">
              <i class="fas fa-stop"></i> 停止播放
            </button>
          </div>
          <div class="file-input-wrapper">
            <button class="btn btn-success" id="uploadLocalBtn">
              <i class="fas fa-upload"></i> 上传本地视频
            </button>
            <input
              type="file"
              id="fileInput"
              accept="video/*"
              aria-label="选择本地视频文件"
            />
          </div>
        </div>

        <div class="control-row">
          <div class="btn-group" id="speedBtnGroup">
            <button class="btn btn-secondary" data-speed="0.5" aria-label="0.5倍速">
              <i class="fas fa-tachometer-alt"></i> 0.5x
            </button>
            <button class="btn btn-secondary" data-speed="1" aria-label="1倍速">
              <i class="fas fa-tachometer-alt"></i> 1x
            </button>
            <button class="btn btn-secondary" data-speed="1.5" aria-label="1.5倍速">
              <i class="fas fa-tachometer-alt"></i> 1.5x
            </button>
            <button class="btn btn-secondary" data-speed="2" aria-label="2倍速">
              <i class="fas fa-tachometer-alt"></i> 2x
            </button>
          </div>
        </div>

        <!-- 新的字幕控制行 -->
        <div class="control-row">
          <div class="subtitle-controls-group">
            <select id="subtitleSelect" class="btn btn-secondary" aria-label="选择字幕">
              <option value="none">无字幕</option>
              <!-- 上传字幕选项将通过JS动态添加 -->
            </select>
            <button class="btn btn-secondary" id="uploadSubtitleBtn" aria-label="上传字幕文件">
              <i class="fas fa-file-upload"></i> 上传字幕
            </button>
            <button class="btn btn-secondary" id="toggleSubtitleBtn" aria-label="显示/隐藏字幕">
              <i class="fas fa-eye-slash"></i> 切换字幕
            </button>
            <button class="btn btn-secondary" onclick="downloadVideo()" aria-label="下载视频">
              <i class="fas fa-download"></i> 下载视频
            </button>
            <!-- 字幕大小和颜色调节 -->
            <div class="subtitle-size-color-controls">
              <label for="subtitleSizeSlider" class="subtitle-label">字幕大小:</label>
              <input type="range" id="subtitleSizeSlider" min="12" max="48" value="20" aria-label="字幕大小" class="subtitle-range-slider" />
              <div class="input-with-unit">
                <input type="number" id="subtitleSizeValue" min="12" max="48" value="20" aria-label="字幕大小数值" class="custom-input-number" />
                <span class="unit-text">px</span>
              </div>
              <label for="subtitleColorPicker" class="subtitle-label">颜色:</label>
              <input type="color" id="subtitleColorPicker" value="#FFFFFF" aria-label="字幕颜色" class="custom-input-color" />
            </div>
          </div>
        </div>

        <div id="statusIndicator" class="status-indicator stopped">
          <i class="fas fa-circle"></i> 播放器已停止
        </div>
      </section>
    </main>
  </div>

  <!-- 设置面板抽屉 -->
  <aside class="drawer-panel settings-panel-drawer" id="settingsPanel">
    <div class="drawer-header">
      <span class="drawer-title-wrapper"><i class="fas fa-cog"></i> 播放器设置</span>
      <button class="close-btn" id="closeSettingsBtn" aria-label="关闭设置面板">
        <i class="fas fa-times"></i>
      </button>
    </div>
    <div class="drawer-content">
      <div class="setting-group">
        <h4><i class="fas fa-image"></i> 背景定制</h4>
        <div class="input-group" style="margin-bottom: var(--spacing-sm);">
          <input type="text" id="backgroundURL" placeholder="背景图片URL" aria-label="背景图片URL" />
          <button class="btn btn-secondary" id="applyBackgroundBtn">应用</button>
        </div>
        <div class="slider-group">
          <label for="backgroundBlurSlider">模糊度:</label>
          <input type="range" id="backgroundBlurSlider" min="0" max="20" step="1" value="5" aria-label="背景模糊度" />
          <span id="backgroundBlurValue">5px</span>
        </div>
        <button class="btn btn-secondary btn-full-width" id="resetBackgroundBtn">
          <i class="fas fa-redo-alt"></i> 重置背景
        </button>
      </div>

      <!-- 字幕样式已移动 -->

      <div class="setting-group">
        <h4><i class="fas fa-film"></i> 画面调节</h4>
        <div class="btn-group" style="margin-bottom: var(--spacing-sm);">
          <button class="btn btn-secondary" id="rotate90Btn"><i class="fas fa-redo-alt"></i> 旋转 90°</button>
          <button class="btn btn-secondary" id="flipXBtn"><i class="fas fa-arrows-alt-h"></i> 水平镜像</button>
          <button class="btn btn-secondary" id="flipYBtn"><i class="fas fa-arrows-alt-v"></i> 垂直镜像</button>
        </div>
        <div class="slider-group">
          <label for="zoomSlider">缩放:</label>
          <input type="range" id="zoomSlider" min="50" max="300" step="1" value="100" aria-label="画面缩放" />
          <span id="zoomValue">100%</span>
        </div>
        <button class="btn btn-secondary btn-full-width" id="resetTransformBtn">
          <i class="fas fa-sync-alt"></i> 重置画面
        </button>
      </div>

      <div class="setting-group">
        <h4><i class="fas fa-palette"></i> 滤镜调节</h4>
        <div class="slider-group">
          <label for="brightnessSlider">亮度:</label>
          <input type="range" id="brightnessSlider" min="0" max="200" step="1" value="100" aria-label="亮度" />
          <span id="brightnessValue">100%</span>
        </div>
        <div class="slider-group">
          <label for="contrastSlider">对比度:</label>
          <input type="range" id="contrastSlider" min="0" max="200" step="1" value="100" aria-label="对比度" />
          <span id="contrastValue">100%</span>
        </div>
        <div class="slider-group">
          <label for="saturationSlider">饱和度:</label>
          <input type="range" id="saturationSlider" min="0" max="200" step="1" value="100" aria-label="饱和度" />
          <span id="saturationValue">100%</span>
        </div>
        <div class="slider-group">
          <label for="sharpenSlider">锐化:</label>
          <input type="range" id="sharpenSlider" min="0" max="10" step="1" value="0" aria-label="锐化" />
          <span id="sharpenValue">0</span>
        </div>

        <div class="btn-group preset-buttons" id="filterPresetsContainer" style="margin-top: var(--spacing-sm);">
          <button class="btn btn-secondary preset-btn" data-preset="vibrant">鲜艳</button>
          <button class="btn btn-secondary preset-btn" data-preset="cinematic">电影</button>
          <button class="btn btn-secondary preset-btn" data-preset="monochrome">黑白</button>
        </div>
        <button class="btn btn-secondary btn-full-width" id="resetFilterBtn">
          <i class="fas fa-sync-alt"></i> 重置滤镜
        </button>
      </div>
    </div>
  </aside>

  <!-- 历史记录面板抽屉 -->
  <aside class="drawer-panel history-panel-drawer" id="historyPanel">
    <div class="drawer-header">
      <span class="drawer-title-wrapper">
        <i class="fas fa-history"></i> <!-- 图标保持在左侧 -->
        <span class="history-title-text">播放历史</span> <!-- 文字左对齐 -->
      </span>
      <button class="close-btn" id="closeHistoryBtn" aria-label="关闭历史记录面板">
        <i class="fas fa-times"></i>
      </button>
    </div>
    <div class="drawer-content">
      <div class="history-loop-controls"> <!-- 新增的循环模式按钮组 -->
        <button class="btn btn-danger btn-sm" onclick="clearHistory()">
          <i class="fas fa-trash"></i> 清空
        </button>
        <button class="btn btn-secondary btn-sm" id="loopSingleBtn" data-loop-mode="single" aria-label="单曲循环">
          <i class="fas fa-redo-alt"></i> 单曲
        </button>
        <button class="btn btn-secondary btn-sm" id="loopListBtn" data-loop-mode="list" aria-label="列表循环">
          <i class="fas fa-list-ul"></i> 列表
        </button>
        <button class="btn btn-secondary btn-sm" id="loopShuffleBtn" data-loop-mode="shuffle" aria-label="随机播放">
          <i class="fas fa-random"></i> 随机
        </button>
      </div>
      <div class="history-list" id="historyList">
        <!-- 历史记录将通过JS动态添加 -->
      </div>
    </div>
  </aside>

  <!-- SVG 滤镜定义，用于锐化效果 -->
  <svg id="sharpen-svg-filters" style="display:none;width:0;height:0;position:absolute;">
    <!-- 滤镜将通过 JavaScript 动态生成 -->
  </svg>

  <script>
    // ====================================================================
    // 全局变量和初始化
    // ====================================================================
    let hlsInstance = null;
    let flvPlayer = null;
    let currentVideoUrl = null; // 当前播放视频的URL (可以是网络URL或blob:URL)
    let currentLocalFileObject = null; // 存储当前播放的本地文件对象
    let currentLocalFileName = null; // 存储当前播放的本地文件名
    let playbackHistory = JSON.parse(localStorage.getItem('playbackHistory')) || []; // 播放历史记录
    let currentSubtitleTracks = []; // 存储解析后的字幕对象 { start, end, text }
    let subtitleActive = false; // 控制自定义字幕显示是否激活
    let currentSubtitleFileName = null; // 当前加载的字幕文件名
    let isSeeking = false; // 用于标记用户是否正在拖动进度条
    let wasPlayingBeforeSeek = false; // 用于记录拖动进度条前视频是否在播放
    let currentlyEditingIndex = -1; // 用于跟踪当前正在编辑的历史项索引
    let currentLoopMode = localStorage.getItem('loopMode') || 'none'; // 循环模式：'none', 'single', 'list', 'shuffle'
    let currentPlayingHistoryIndex = -1; // 跟踪当前播放的视频在历史记录中的索引

    // 自定义控制条自动隐藏相关
    let controlsHideTimeout = null;
    const controlsVisibleDuration = 3000; // 3秒后自动隐藏

    // 支持的视频格式列表 (用于文件扩展名检查)
    const supportedFormats = [
      'mp4', 'm3u8', 'flv', 'webm', 'mkv', 'mov', 'avi', 'wmv', '3gp', 'ogg', 'mpg', 'mpeg', 'vob', 'ts',
    ];

    // 字幕设置的默认值
    const defaultSubtitleSettings = {
      fontSize: 20,
      color: '#FFFFFF',
    };
    let currentSubtitleSettings = JSON.parse(localStorage.getItem('subtitleSettings')) || defaultSubtitleSettings;

    // 视频画面变换设置
    const defaultTransformSettings = {
      rotate: 0,
      scaleX: 1,
      scaleY: 1,
      zoom: 100,
    };
    let transformSettings = JSON.parse(localStorage.getItem('transformSettings')) || { ...defaultTransformSettings };

    // 视频滤镜设置
    const defaultFilterSettings = {
      brightness: 100,
      contrast: 100,
      saturation: 100,
      sharpen: 0,
    };
    let filterSettings = JSON.parse(localStorage.getItem('filterSettings')) || { ...defaultFilterSettings };

    // 滤镜预设值
    const filterPresets = {
      vibrant: { brightness: 105, contrast: 110, saturation: 150, sharpen: 0 },
      cinematic: { brightness: 95, contrast: 120, saturation: 80, sharpen: 0 },
      monochrome: { brightness: 100, contrast: 100, saturation: 0, sharpen: 0 },
    };

    // 背景设置
    const defaultBackgroundSettings = {
      url: 'https://bing.img.run/uhd.php', // 初始默认背景图
      blur: 0, // 修改默认模糊度为0
    };
    let backgroundSettings = JSON.parse(localStorage.getItem('backgroundSettings')) || { ...defaultBackgroundSettings };

    // 播放器DOM元素引用 (使用 let 声明，方便在 DOMContentLoaded 中赋值)
    let videoPlayer, playPauseBtn, playPauseIcon,
        uploadPlaceholder, videoContainerElement,
        seekSlider, currentTimeDisplay, durationDisplay,
        volumeSlider, volumeIcon, muteButtonIcon, volumePercentageDisplay,
        subtitleSizeSlider, subtitleSizeValue, subtitleColorPicker, subtitleDisplay,
        settingsPanel, historyPanel,
        rotate90Btn, flipXBtn, flipYBtn, zoomSlider, zoomValueSpan, resetTransformBtn,
        brightnessSlider, brightnessValueSpan, contrastSlider, contrastValueSpan,
        saturationSlider, saturationValueSpan, sharpenSlider, sharpenValueSpan,
        resetFilterBtn, filterPresetsContainer, speedBtnGroup,
        backgroundURLInput, backgroundBlurSlider, backgroundBlurValueSpan, applyBackgroundBtn, resetBackgroundBtn,
        headerSettingsToggleBtn, headerHistoryToggleBtn,
        // 视频内部控制条元素
        inVideoControls, inVideoPlayPauseBtn, inVideoPlayPauseIcon,
        inVideoSeekSlider, inVideoCurrentTimeDisplay, inVideoDurationDisplay,
        inVideoVolumeSlider, inVideoVolumeIcon, inVideoVolumePercentageDisplay, inVideoFullscreenBtn,
        loopSingleBtn, loopListBtn, loopShuffleBtn;


    // ====================================================================
    // DOMContentLoaded 事件监听器
    // ====================================================================
    document.addEventListener('DOMContentLoaded', function () {
      // 获取DOM元素引用
      videoPlayer = document.getElementById('videoPlayer');
      playPauseBtn = document.getElementById('playPauseBtn');
      playPauseIcon = playPauseBtn.querySelector('i');
      uploadPlaceholder = document.getElementById('uploadPlaceholder');
      videoContainerElement = document.getElementById('videoContainer');
      seekSlider = document.getElementById('seekSlider');
      currentTimeDisplay = document.getElementById('currentTimeDisplay');
      durationDisplay = document.getElementById('durationDisplay');
      volumeSlider = document.getElementById('volumeSlider');
      volumeIcon = document.getElementById('volumeIcon');
      muteButtonIcon = document.getElementById('muteButtonIcon');
      volumePercentageDisplay = document.getElementById('volumePercentageDisplay');
      subtitleSizeSlider = document.getElementById('subtitleSizeSlider');
      subtitleSizeValue = document.getElementById('subtitleSizeValue');
      subtitleColorPicker = document.getElementById('subtitleColorPicker');
      subtitleDisplay = document.getElementById('subtitleDisplay');

      settingsPanel = document.getElementById('settingsPanel');
      historyPanel = document.getElementById('historyPanel');

      // 画面调节
      rotate90Btn = document.getElementById('rotate90Btn');
      flipXBtn = document.getElementById('flipXBtn');
      flipYBtn = document.getElementById('flipYBtn');
      zoomSlider = document.getElementById('zoomSlider');
      zoomValueSpan = document.getElementById('zoomValue');
      resetTransformBtn = document.getElementById('resetTransformBtn');

      // 滤镜调节
      brightnessSlider = document.getElementById('brightnessSlider');
      brightnessValueSpan = document.getElementById('brightnessValue');
      contrastSlider = document.getElementById('contrastSlider');
      contrastValueSpan = document.getElementById('contrastValue');
      saturationSlider = document.getElementById('saturationSlider');
      saturationValueSpan = document.getElementById('saturationValue');
      sharpenSlider = document.getElementById('sharpenSlider');
      sharpenValueSpan = document.getElementById('sharpenValue');
      resetFilterBtn = document.getElementById('resetFilterBtn');
      filterPresetsContainer = document.getElementById('filterPresetsContainer');

      // 速度控制组
      speedBtnGroup = document.getElementById('speedBtnGroup');

      // 背景定制
      backgroundURLInput = document.getElementById('backgroundURL');
      backgroundBlurSlider = document.getElementById('backgroundBlurSlider');
      backgroundBlurValueSpan = document.getElementById('backgroundBlurValue');
      applyBackgroundBtn = document.getElementById('applyBackgroundBtn');
      resetBackgroundBtn = document.getElementById('resetBackgroundBtn');

      // 头部切换按钮
      headerSettingsToggleBtn = document.getElementById('headerSettingsToggleBtn');
      headerHistoryToggleBtn = document.getElementById('headerHistoryToggleBtn');

      // 视频内部控制条元素
      inVideoControls = document.getElementById('inVideoControls');
      inVideoPlayPauseBtn = document.getElementById('inVideoPlayPauseBtn');
      inVideoPlayPauseIcon = inVideoPlayPauseBtn.querySelector('i');
      inVideoSeekSlider = document.getElementById('inVideoSeekSlider');
      inVideoCurrentTimeDisplay = document.getElementById('inVideoCurrentTimeDisplay');
      inVideoDurationDisplay = document.getElementById('inVideoDurationDisplay');
      inVideoVolumeSlider = document.getElementById('inVideoVolumeSlider');
      inVideoVolumeIcon = document.getElementById('inVideoVolumeIcon');
      inVideoVolumePercentageDisplay = document.getElementById('inVideoVolumePercentageDisplay');
      inVideoFullscreenBtn = document.getElementById('inVideoFullscreenBtn');

      // 循环模式按钮
      loopSingleBtn = document.getElementById('loopSingleBtn');
      loopListBtn = document.getElementById('loopListBtn');
      loopShuffleBtn = document.getElementById('loopShuffleBtn');


      // 加载主题设置
      loadTheme();

      // 渲染历史记录
      renderHistory();

      // 设置拖放区域功能
      setupDragAndDrop();

      // 点击上传占位符区域触发文件选择
      uploadPlaceholder.addEventListener('click', () => {
          if (!videoContainerElement.classList.contains('visible')) {
              document.getElementById('fileInput').click();
          }
      });

      // 设置播放器事件监听 (包含进度条)
      setupPlayerEvents();

      // 设置音量控制
      setupVolumeControl();
      setupInVideoVolumeControl(); // 新增：设置视频内部音量控制

      // 设置字幕样式控制
      setupSubtitleSettings();

      // 设置侧边抽屉面板的开关逻辑
      setupPanelToggles();

      // 设置画面调节和滤镜控制
      setupVideoSettingsControls();

      // 设置背景定制功能
      setupBackgroundCustomization();

      // 创建锐化滤镜的 SVG 元素
      createSharpenSVGElements();

      // 加载所有保存的设置 (字幕、画面、滤镜、播放速度、背景)
      loadAllSettings();

      // 绑定上传本地视频按钮
      document.getElementById('uploadLocalBtn').addEventListener('click', () => {
        document.getElementById('fileInput').click();
      });

      // 绑定上传字幕按钮
      document.getElementById('uploadSubtitleBtn').addEventListener('click', () => {
        uploadSubtitleFile();
      });

      // 监听本地视频文件选择
      document.getElementById('fileInput').addEventListener('change', function () {
        if (this.files && this.files[0]) {
          playLocalVideo(this.files[0]);
          this.value = ''; // 清空，允许重复上传同一个文件也触发
        }
      });

      // 绑定加载视频按钮的点击事件 (取代了原来的 playPauseBtn 的加载功能)
      document.getElementById('loadVideoBtn').addEventListener('click', () => {
        const inputUrl = document.getElementById('videoURL').value.trim();
        if (inputUrl) {
          play(inputUrl);
        } else {
          alert('请输入视频URL！');
        }
      });

      // 绑定重新加载按钮的点击事件
      document.getElementById('reloadVideoBtn').addEventListener('click', reloadVideo);

      // 绑定URL输入框的回车事件
      document.getElementById('videoURL').addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
          e.preventDefault();
          document.getElementById('loadVideoBtn').click();
        }
      });

      // 绑定播放/暂停按钮的点击事件 (仅切换播放状态，不加载新视频)
      playPauseBtn.addEventListener('click', togglePlayPause);
      inVideoPlayPauseBtn.addEventListener('click', togglePlayPause); // 视频内部控制条的播放/暂停按钮

      // 绑定视频内部控制条的全屏按钮
      inVideoFullscreenBtn.addEventListener('click', toggleFullscreen);

      // 为历史记录列表添加事件委托，处理编辑/保存按钮点击
      document.getElementById('historyList').addEventListener('click', function(e) {
        const targetBtn = e.target.closest('.edit-save-btn');
        if (targetBtn) {
          const index = parseInt(targetBtn.dataset.index);
          const action = targetBtn.dataset.action;

          if (action === 'edit') {
            startEditMode(index);
          } else if (action === 'save' && currentlyEditingIndex === index) {
            saveEditMode(index);
          }
        }
      });

      // 监听全屏状态变化，以便调整视频样式
      document.addEventListener('fullscreenchange', handleFullscreenChange);

      // 绑定播放速度按钮
      speedBtnGroup.addEventListener('click', (e) => {
        const targetBtn = e.target.closest('.btn');
        if (targetBtn && targetBtn.dataset.speed) {
          changeSpeed(parseFloat(targetBtn.dataset.speed), targetBtn);
        }
      });

      // 绑定字幕显示/隐藏按钮
      document.getElementById('toggleSubtitleBtn').addEventListener('click', toggleSubtitle);

      // 绑定静音按钮的点击事件
      document.getElementById('muteButton').addEventListener('click', toggleMute);

      // 添加全局点击事件监听器，用于关闭面板
      document.addEventListener('click', handleOutsideClick);

      // 绑定键盘事件
      document.addEventListener('keydown', handleKeyDown);

      // 绑定视频双击事件
      videoPlayer.addEventListener('dblclick', toggleFullscreen);

      // 绑定循环模式按钮事件
      document.querySelector('.history-loop-controls').addEventListener('click', (e) => {
          const targetBtn = e.target.closest('.btn');
          if (targetBtn && targetBtn.dataset.loopMode) {
              setLoopMode(targetBtn.dataset.loopMode);
          }
      });
      updateLoopModeButtons(); // 初始化循环模式按钮状态

      // --- 自定义控制条自动隐藏/显示逻辑 ---
      // 初始状态：如果不是桌面端，则显示控制条并启动隐藏计时器
      if (window.innerWidth <= 768) { // Mobile
        inVideoControls.classList.add('controls-visible');
        resetHideTimer(); // Start hide timer for mobile
      } else { // Desktop
        // Controls start hidden, will show on mousemove
        inVideoControls.classList.remove('controls-visible');
      }

      // 桌面端鼠标事件
      if (window.innerWidth > 768) {
        videoContainerElement.addEventListener('mousemove', showControls);
        videoContainerElement.addEventListener('mouseleave', resetHideTimer);
        // PC端点击视频区域播放/暂停
        videoPlayer.addEventListener('click', togglePlayPause);

        // 确保在控制条元素上移动鼠标也能保持显示
        inVideoControls.addEventListener('mousemove', showControls);
        inVideoControls.addEventListener('mouseleave', resetHideTimer);

        // 任何对控制条内部交互元素的鼠标事件都应重置计时器
        const interactiveElements = inVideoControls.querySelectorAll('button, input[type="range"]');
        interactiveElements.forEach(el => {
          el.addEventListener('mousemove', showControls);
          el.addEventListener('mousedown', showControls);
          el.addEventListener('mouseup', showControls);
        });
      } else { // 移动端点击事件
        videoContainerElement.addEventListener('click', function() {
          if (inVideoControls.classList.contains('controls-visible')) {
            hideControls();
            clearTimeout(controlsHideTimeout); // Clear timeout if user explicitly hides
          } else {
            showControls(); // Show and start hide timer
          }
        });
      }

      // 视频播放时显示控制条并启动计时器
      videoPlayer.addEventListener('play', function() {
        showControls();
      });

      // 视频暂停时保持控制条显示，停止计时器
      videoPlayer.addEventListener('pause', function() {
        clearTimeout(controlsHideTimeout);
        inVideoControls.classList.add('controls-visible');
      });
    });

    // ====================================================================
    // UI/UX 交互功能
    // ====================================================================

    /**
     * 显示视频内部控制条并重置自动隐藏计时器。
     */
    function showControls() {
      inVideoControls.classList.add('controls-visible');
      resetHideTimer();
    }

    /**
     * 隐藏视频内部控制条。
     */
    function hideControls() {
      // inVideoControls.classList.remove('controls-visible');
    }

    /**
     * 重置自动隐藏计时器。
     */
    function resetHideTimer() {
      clearTimeout(controlsHideTimeout);
      // 只有在视频播放且不是暂停状态时才启动自动隐藏
      if (!videoPlayer.paused && window.innerWidth > 768) { // 桌面端才自动隐藏
        controlsHideTimeout = setTimeout(hideControls, controlsVisibleDuration);
      } else if (!videoPlayer.paused && window.innerWidth <= 768) { // 移动端也自动隐藏，但通过点击触发
        controlsHideTimeout = setTimeout(hideControls, controlsVisibleDuration);
      }
    }


    /**
     * 处理点击事件，用于关闭侧边抽屉面板。
     * 如果点击发生在面板外部或触发按钮外部，则关闭面板。
     */
    function handleOutsideClick(event) {
        // 头部按钮
        const headerSettingsToggleBtn = document.getElementById('headerSettingsToggleBtn');
        const headerHistoryToggleBtn = document.getElementById('headerHistoryToggleBtn');

        // 检查点击是否在设置面板或其触发按钮之外
        const isClickInsideSettingsPanel = settingsPanel.contains(event.target) ||
                                           (headerSettingsToggleBtn && headerSettingsToggleBtn.contains(event.target));
        if (settingsPanel.classList.contains('open') && !isClickInsideSettingsPanel) {
            settingsPanel.classList.remove('open');
        }

        // 检查点击是否在历史面板或其触发按钮之外
        const isClickInsideHistoryPanel = historyPanel.contains(event.target) ||
                                          (headerHistoryToggleBtn && headerHistoryToggleBtn.contains(event.target));
        if (historyPanel.classList.contains('open') && !isClickInsideHistoryPanel) {
            historyPanel.classList.remove('open');
        }
    }

    /**
     * 处理全屏状态变化，调整视频容器样式。
     */
    function handleFullscreenChange() {
        if (document.fullscreenElement) {
            videoContainerElement.classList.add('fullscreen-active');
            showControls(); // 进入全屏时显示控制条并启动计时器
        } else {
            videoContainerElement.classList.remove('fullscreen-active');
            // 退出全屏时，根据当前设备类型恢复控制条的显示逻辑
            if (window.innerWidth > 768) { // 桌面端
                resetHideTimer(); // 启动自动隐藏计时器
            } else { // 移动端
                // 移动端在点击后会再次触发 showControls，这里不需要额外处理
                // 如果控制条当前可见，也启动隐藏计时器
                if (inVideoControls.classList.contains('controls-visible')) {
                    resetHideTimer();
                }
            }
        }
        applyVideoTransformations(); // 全屏/退出全屏后重新应用变换
        applyVideoFilters(); // 全屏/退出全屏后重新应用滤镜
    }

    /**
     * 设置侧边抽屉面板的开关逻辑。
     */
    function setupPanelToggles() {
      // 头部按钮监听 (桌面/移动端通用)
      if (headerSettingsToggleBtn) {
        headerSettingsToggleBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          settingsPanel.classList.toggle('open');
          historyPanel.classList.remove('open'); // 关闭另一个面板
          adjustPanelTopPosition(settingsPanel); // 调整面板位置
        });
      }
      if (headerHistoryToggleBtn) {
        headerHistoryToggleBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          historyPanel.classList.toggle('open');
          settingsPanel.classList.remove('open'); // 关闭另一个面板
          adjustPanelTopPosition(historyPanel); // 调整面板位置
        });
      }

      // 关闭按钮
      document.getElementById('closeSettingsBtn').addEventListener('click', () => {
        settingsPanel.classList.remove('open');
      });
      document.getElementById('closeHistoryBtn').addEventListener('click', () => {
        historyPanel.classList.remove('open');
      });
    }

    /**
     * 根据头部高度调整面板的 top 位置，确保不被遮挡。
     */
    function adjustPanelTopPosition(panel) {
      const header = document.querySelector('.header');
      if (header && panel) {
        const headerHeight = header.offsetHeight;
        // 考虑到 body 的 padding-top (var(--spacing-md))
        const bodyPaddingTop = parseFloat(getComputedStyle(document.body).paddingTop);
        panel.style.top = `${headerHeight + bodyPaddingTop + 10}px`; // 头部高度 + body顶部内边距 + 额外间距
        panel.style.maxHeight = `calc(100vh - ${headerHeight + bodyPaddingTop + 20}px)`; // 调整最大高度
      }
    }

    /**
     * 设置视频画面调节和滤镜控制。
     */
    function setupVideoSettingsControls() {
      // 画面变换控制
      rotate90Btn.addEventListener('click', () => {
        transformSettings.rotate = (transformSettings.rotate + 90) % 360;
        applyVideoTransformations();
        saveAllSettings();
      });

      flipXBtn.addEventListener('click', () => {
        transformSettings.scaleX *= -1;
        applyVideoTransformations();
        saveAllSettings();
      });

      flipYBtn.addEventListener('click', () => {
        transformSettings.scaleY *= -1;
        applyVideoTransformations();
        saveAllSettings();
      });

      zoomSlider.addEventListener('input', () => {
        transformSettings.zoom = parseInt(zoomSlider.value);
        zoomValueSpan.textContent = `${transformSettings.zoom}%`;
        applyVideoTransformations();
        saveAllSettings();
      });

      resetTransformBtn.addEventListener('click', () => {
        Object.assign(transformSettings, defaultTransformSettings);
        zoomSlider.value = transformSettings.zoom;
        zoomValueSpan.textContent = `${transformSettings.zoom}%`;
        applyVideoTransformations();
        saveAllSettings();
      });

      // 视频滤镜控制
      brightnessSlider.addEventListener('input', () => {
        filterSettings.brightness = parseInt(brightnessSlider.value);
        brightnessValueSpan.textContent = `${filterSettings.brightness}%`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      contrastSlider.addEventListener('input', () => {
        filterSettings.contrast = parseInt(contrastSlider.value);
        contrastValueSpan.textContent = `${filterSettings.contrast}%`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      saturationSlider.addEventListener('input', () => {
        filterSettings.saturation = parseInt(saturationSlider.value);
        saturationValueSpan.textContent = `${filterSettings.saturation}%`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      sharpenSlider.addEventListener('input', () => {
        filterSettings.sharpen = parseInt(sharpenSlider.value);
        sharpenValueSpan.textContent = `${filterSettings.sharpen}`;
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      resetFilterBtn.addEventListener('click', () => {
        Object.assign(filterSettings, defaultFilterSettings);
        updateFilterSlidersUI();
        clearActiveFilterPreset();
        applyVideoFilters();
        saveAllSettings();
      });

      filterPresetsContainer.addEventListener('click', (e) => {
        const targetBtn = e.target.closest('.preset-btn');
        if (targetBtn && targetBtn.dataset.preset) {
          const preset = filterPresets[targetBtn.dataset.preset];
          if (preset) {
            Object.assign(filterSettings, preset);
            updateFilterSlidersUI();
            clearActiveFilterPreset();
            targetBtn.classList.add('active-preset');
            applyVideoFilters();
            saveAllSettings();
          }
        }
      });
    }

    /**
     * 设置背景定制功能。
     */
    function setupBackgroundCustomization() {
      backgroundURLInput.value = backgroundSettings.url;
      backgroundBlurSlider.value = backgroundSettings.blur;
      backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
      applyBackground(); // 初始应用

      applyBackgroundBtn.addEventListener('click', () => {
        backgroundSettings.url = backgroundURLInput.value.trim();
        applyBackground();
        saveAllSettings();
      });

      backgroundBlurSlider.addEventListener('input', () => {
        backgroundSettings.blur = parseInt(backgroundBlurSlider.value);
        backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
        applyBackground();
        saveAllSettings();
      });

      resetBackgroundBtn.addEventListener('click', () => {
        Object.assign(backgroundSettings, defaultBackgroundSettings);
        backgroundURLInput.value = backgroundSettings.url;
        backgroundBlurSlider.value = backgroundSettings.blur;
        backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
        applyBackground();
        saveAllSettings();
      });
    }

    /**
     * 应用背景图片和模糊度。
     */
    function applyBackground() {
      // 如果 backgroundSettings.url 为空字符串，则不设置背景图片
      const imageUrl = backgroundSettings.url ? `url('${backgroundSettings.url}')` : 'none';
      document.body.style.setProperty('--player-bg-image', imageUrl);
      document.body.style.setProperty('--player-bg-blur', `${backgroundSettings.blur}px`);
    }

    /**
     * 应用视频画面变换。
     */
    function applyVideoTransformations() {
      if (!videoPlayer) return;
      videoPlayer.style.transform = `rotate(${transformSettings.rotate}deg) scaleX(${transformSettings.scaleX}) scaleY(${transformSettings.scaleY}) scale(${transformSettings.zoom / 100})`;
    }

    /**
     * 应用视频滤镜。
     */
    function applyVideoFilters() {
      if (!videoPlayer) return;
      let filterStyle = `brightness(${filterSettings.brightness}%) contrast(${filterSettings.contrast}%) saturate(${filterSettings.saturation}%)`;
      if (filterSettings.sharpen > 0 && filterSettings.sharpen <= 10) {
        // 使用 SVG 滤镜进行锐化
        filterStyle += ` url(#sharpen-filter-${filterSettings.sharpen})`;
      }
      videoPlayer.style.filter = filterStyle;
    }

    /**
     * 更新滤镜滑块 UI。
     */
    function updateFilterSlidersUI() {
      brightnessSlider.value = filterSettings.brightness;
      brightnessValueSpan.textContent = `${filterSettings.brightness}%`;
      contrastSlider.value = filterSettings.contrast;
      contrastValueSpan.textContent = `${filterSettings.contrast}%`;
      saturationSlider.value = filterSettings.saturation;
      saturationValueSpan.textContent = `${filterSettings.saturation}%`;
      sharpenSlider.value = filterSettings.sharpen;
      sharpenValueSpan.textContent = `${filterSettings.sharpen}`;
    }

    /**
     * 清除激活的滤镜预设按钮样式。
     */
    function clearActiveFilterPreset() {
      document.querySelectorAll('#filterPresetsContainer .preset-btn').forEach(btn => btn.classList.remove('active-preset'));
    }

    /**
     * 获取锐化矩阵值。
     */
    function getSharpenMatrix(level) {
      if (level === 0) return '';
      // 锐化矩阵的中心值和边缘值会根据 level 变化
      const baseK = 5; // 基础中心值
      const maxKBoost = 8; // 中心值最大增量
      const edgeBase = -0.5; // 基础边缘值
      const maxEdgeBoost = -1.0; // 边缘值最大减量 (负值)

      const kValue = baseK + (maxKBoost * (level - 1) / 9); // 中心值
      const eValue = edgeBase + (maxEdgeBoost * (level - 1) / 9); // 边缘值

      const k = kValue.toFixed(2);
      const e = eValue.toFixed(2);

      // 3x3 锐化卷积核
      return `${e} ${e} ${e} ${e} ${k} ${e} ${e} ${e} ${e}`;
    }

    /**
     * 创建锐化滤镜的 SVG 元素。
     */
    function createSharpenSVGElements() {
      const svgNS = "http://www.w3.org/2000/svg"; // 注意：SVG命名空间是http://，不是https://
      let svgContainer = document.getElementById('sharpen-svg-filters');

      svgContainer.innerHTML = ''; // 清空现有滤镜，防止重复添加

      for (let i = 1; i <= 10; i++) { // 从 1 到 10 级锐化
        const filterId = `sharpen-filter-${i}`;
        const matrixValue = getSharpenMatrix(i);

        const filterElement = document.createElementNS(svgNS, 'filter');
        filterElement.setAttribute('id', filterId);

        const convolveMatrix = document.createElementNS(svgNS, 'feConvolveMatrix');
        convolveMatrix.setAttribute('order', '3'); // 3x3 矩阵
        convolveMatrix.setAttribute('kernelMatrix', matrixValue);
        convolveMatrix.setAttribute('divisor', '1'); // 默认除数，通常用于归一化
        convolveMatrix.setAttribute('bias', '0'); // 默认偏差

        filterElement.appendChild(convolveMatrix);
        svgContainer.appendChild(filterElement);
      }
    }

    /**
     * 设置拖放区域功能。
     */
    function setupDragAndDrop() {
      const uploadArea = document.getElementById('uploadPlaceholder');
      const fileInput = document.getElementById('fileInput');

      // 阻止默认的拖放行为
      ['dragenter', 'dragover', 'dragleave', 'drop'].forEach((eventName) => {
        document.body.addEventListener(eventName, preventDefaults, false); // 全局阻止
        uploadArea.addEventListener(eventName, preventDefaults, false); // 针对上传区域阻止
      });

      function preventDefaults(e) {
        e.preventDefault();
        e.stopPropagation();
      }

      // 拖入/拖出时的样式变化
      ['dragenter', 'dragover'].forEach((eventName) => {
        uploadArea.addEventListener(
          eventName,
          () => {
            uploadArea.classList.add('drag-over');
          },
          false
        );
      });

      ['dragleave', 'drop'].forEach((eventName) => {
        uploadArea.addEventListener(
          eventName,
          () => {
            uploadArea.classList.remove('drag-over');
          },
          false

        );
      });

      // 处理文件拖放
      uploadArea.addEventListener(
        'drop',
        function handleDrop(e) {
          const dt = e.dataTransfer;
          const files = dt.files;

          if (files && files.length) {
            const file = files[0];
            const fileName = file.name.toLowerCase();

            if (fileName.endsWith('.srt') || fileName.endsWith('.vtt')) {
              // 处理字幕文件
              const reader = new FileReader();
              reader.onload = function (event) {
                parseAndActivateSubtitle(event.target.result);
                currentSubtitleFileName = file.name;
                updateSubtitleSelectLabel(file.name);
              };
              reader.readAsText(file);
            } else if (file.type.startsWith('video/')) {
              // 处理视频文件
              playLocalVideo(file);
            } else {
              alert('不支持的文件类型。请拖放视频或字幕文件 (.srt, .vtt)。');
            }
          }
        },
        false
      );
    }

    /**
     * 设置播放器事件监听。
     */
    function setupPlayerEvents() {
      videoPlayer.addEventListener('timeupdate', function () {
        if (!isSeeking) {
          seekSlider.value = videoPlayer.currentTime;
          inVideoSeekSlider.value = videoPlayer.currentTime; // 更新视频内部进度条
        }
        currentTimeDisplay.textContent = formatTime(videoPlayer.currentTime);
        inVideoCurrentTimeDisplay.textContent = formatTime(videoPlayer.currentTime); // 更新视频内部时间

        if (subtitleActive && currentSubtitleTracks.length > 0) {
          updateSubtitleDisplay(this.currentTime);
        } else {
          subtitleDisplay.textContent = '';
          subtitleDisplay.style.display = 'none';
        }
      });

      videoPlayer.addEventListener('loadedmetadata', function() {
        seekSlider.max = videoPlayer.duration;
        inVideoSeekSlider.max = videoPlayer.duration; // 更新视频内部进度条最大值
        durationDisplay.textContent = formatTime(videoPlayer.duration);
        inVideoDurationDisplay.textContent = formatTime(videoPlayer.duration); // 更新视频内部总时长
        currentTimeDisplay.textContent = formatTime(videoPlayer.currentTime);
        inVideoCurrentTimeDisplay.textContent = formatTime(videoPlayer.currentTime); // 更新视频内部时间
      });

      videoPlayer.addEventListener('play', function () {
        updateStatus('playing', `正在播放 (${videoPlayer.playbackRate}x)`);
        playPauseIcon.className = 'fas fa-pause';
        inVideoPlayPauseIcon.className = 'fas fa-pause'; // 更新视频内部按钮
        uploadPlaceholder.classList.add('hidden');
        videoContainerElement.classList.add('visible');
      });

      videoPlayer.addEventListener('pause', function () {
        updateStatus('stopped', '播放已暂停');
        playPauseIcon.className = 'fas fa-play';
        inVideoPlayPauseIcon.className = 'fas fa-play'; // 更新视频内部按钮
      });

      videoPlayer.addEventListener('waiting', function () {
        updateStatus('loading', '正在缓冲...');
      });

      videoPlayer.addEventListener('ended', function () {
        updateStatus('stopped', '播放已结束');
        // 检查循环模式
        if (currentLoopMode === 'single') {
            videoPlayer.currentTime = 0;
            videoPlayer.play();
            updateStatus('playing', '单曲循环中...');
        } else if (currentLoopMode === 'list') {
            if (playbackHistory.length > 0 && currentPlayingHistoryIndex !== -1) {
                currentPlayingHistoryIndex = (currentPlayingHistoryIndex + 1) % playbackHistory.length;
                playFromHistory(currentPlayingHistoryIndex);
                updateStatus('playing', `列表循环中，播放下一项: ${playbackHistory[currentPlayingHistoryIndex].title}`);
            } else {
                // Fallback if history is empty or index is invalid
                videoPlayer.currentTime = videoPlayer.duration;
                videoPlayer.pause();
            }
        } else if (currentLoopMode === 'shuffle') {
            if (playbackHistory.length > 0) {
                let nextIndex;
                do {
                    nextIndex = Math.floor(Math.random() * playbackHistory.length);
                } while (playbackHistory.length > 1 && nextIndex === currentPlayingHistoryIndex); // Avoid playing same video again if more than one exists

                currentPlayingHistoryIndex = nextIndex;
                playFromHistory(currentPlayingHistoryIndex);
                updateStatus('playing', `随机播放中，播放: ${playbackHistory[currentPlayingHistoryIndex].title}`);
            } else {
                videoPlayer.currentTime = videoPlayer.duration;
                videoPlayer.pause();
            }
        } else {
            // Default behavior (no loop)
            videoPlayer.currentTime = videoPlayer.duration;
            videoPlayer.pause(); // 立即暂停
            videoPlayer.currentTime = videoPlayer.duration; // 精确设置到最后一帧
            seekSlider.value = videoPlayer.duration;
            inVideoSeekSlider.value = videoPlayer.duration; // 更新视频内部进度条
            currentTimeDisplay.textContent = formatTime(videoPlayer.duration);
            inVideoCurrentTimeDisplay.textContent = formatTime(videoPlayer.duration); // 更新视频内部时间
            playPauseIcon.className = 'fas fa-play';
            inVideoPlayPauseIcon.className = 'fas fa-play';
        }
      });

      videoPlayer.addEventListener('error', function () {
        const error = this.error;
        let errorMessage = '未知错误';
        if (error) {
          switch (error.code) {
            case error.MEDIA_ERR_ABORTED:
              errorMessage = '用户终止了播放。';
              break;
            case error.MEDIA_ERR_NETWORK:
              errorMessage = '网络错误导致视频下载失败。';
              break;
            case error.MEDIA_ERR_DECODE:
              errorMessage = '视频解码错误。';
              break;
            case error.MEDIA_ERR_SRC_NOT_SUPPORTED:
              errorMessage = '视频源格式不受支持或文件损坏。';
              break;
            default:
              errorMessage = `错误代码: ${error.code} - ${error.message}`;
              break;
          }
        }
        console.error('播放错误:', error);
        updateStatus('stopped', '播放错误: ' + errorMessage);
        playPauseIcon.className = 'fas fa-play';
        inVideoPlayPauseIcon.className = 'fas fa-play'; // 更新视频内部按钮
        currentLocalFileObject = null;
        uploadPlaceholder.classList.remove('hidden');
        videoContainerElement.classList.remove('visible');
        // 不清空 videoURL 输入框，以便用户修改后重试
        // document.getElementById('videoURL').value = '';
      });

      // 进度条拖动事件 (PC端)
      seekSlider.addEventListener('mousedown', handleSeekStart);
      seekSlider.addEventListener('mouseup', handleSeekEnd);
      inVideoSeekSlider.addEventListener('mousedown', handleSeekStart); // 视频内部进度条
      inVideoSeekSlider.addEventListener('mouseup', handleSeekEnd); // 视频内部进度条

      // 进度条拖动事件 (移动端)
      seekSlider.addEventListener('touchstart', handleSeekStart);
      seekSlider.addEventListener('touchend', handleSeekEnd);
      inVideoSeekSlider.addEventListener('touchstart', handleSeekStart); // 视频内部进度条
      inVideoSeekSlider.addEventListener('touchend', handleSeekEnd); // 视频内部进度条

      function handleSeekStart() {
        isSeeking = true;
        wasPlayingBeforeSeek = !videoPlayer.paused; // 记录拖动前是否在播放
        videoPlayer.pause();
      }

      function handleSeekEnd() {
        isSeeking = false;
        const targetTime = parseFloat(this.value); // 使用触发事件的滑块的值
        const wasPlaying = wasPlayingBeforeSeek; // 捕获本地变量

        // 确保移除所有旧的 seeked 监听器，防止重复触发
        videoPlayer.removeEventListener('seeked', onSeekedResumePlayback);

        videoPlayer.currentTime = targetTime;

        // 添加一个针对当前 seek 操作的新的 seeked 监听器
        videoPlayer.addEventListener('seeked', onSeekedResumePlayback);

        function onSeekedResumePlayback() {
          videoPlayer.removeEventListener('seeked', onSeekedResumePlayback); // 执行后移除自身
          if (wasPlaying) {
            videoPlayer.play().catch(e => console.error("Error playing after seeked:", e));
          }
        }
      }

      seekSlider.addEventListener('input', function() {
        currentTimeDisplay.textContent = formatTime(this.value);
        inVideoSeekSlider.value = this.value; // 同步视频内部进度条
        inVideoCurrentTimeDisplay.textContent = formatTime(this.value); // 同步视频内部时间
      });
      inVideoSeekSlider.addEventListener('input', function() {
        inVideoCurrentTimeDisplay.textContent = formatTime(this.value);
        seekSlider.value = this.value; // 同步外部进度条
        currentTimeDisplay.textContent = formatTime(this.value); // 同步外部时间
      });
    }

    /**
     * 将秒数格式化为 HH:MM:SS 或 MM:SS 格式。
     */
    function formatTime(seconds) {
      const minutes = Math.floor(seconds / 60);
      const remainingSeconds = Math.floor(seconds % 60);
      const hours = Math.floor(minutes / 60);
      const remainingMinutes = Math.floor(minutes % 60);

      if (hours > 0) {
        return `${hours.toString().padStart(2, '0')}:${remainingMinutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
      } else {
        return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
      }
    }

    /**
     * 设置外部音量控制。
     */
    function setupVolumeControl() {
      videoPlayer.volume = volumeSlider.value / 100;
      volumePercentageDisplay.textContent = `${volumeSlider.value}%`; // 初始化音量百分比
      updateMuteButtonIcon();

      volumeSlider.addEventListener('input', function () {
        const volume = this.value / 100;
        videoPlayer.volume = volume;
        volumePercentageDisplay.textContent = `${this.value}%`; // 更新音量百分比
        inVideoVolumeSlider.value = this.value; // 同步视频内部音量滑块
        inVideoVolumePercentageDisplay.textContent = `${this.value}%`; // 同步视频内部音量百分比

        if (volume === 0) {
          volumeIcon.className = 'fas fa-volume-mute';
        } else if (volume < 0.5) {
          volumeIcon.className = 'fas fa-volume-down';
        } else {
          volumeIcon.className = 'fas fa-volume-up';
        }
        updateMuteButtonIcon();
      });

      // 点击音量图标切换静音
      volumeIcon.addEventListener('click', toggleMute);
    }

    /**
     * 设置视频内部音量控制。
     */
    function setupInVideoVolumeControl() {
        inVideoVolumeSlider.value = volumeSlider.value; // 初始化与外部同步
        inVideoVolumePercentageDisplay.textContent = `${inVideoVolumeSlider.value}%`;

        inVideoVolumeSlider.addEventListener('input', function() {
            const volume = this.value / 100;
            videoPlayer.volume = volume;
            inVideoVolumePercentageDisplay.textContent = `${this.value}%`;
            volumeSlider.value = this.value; // 同步外部音量滑块
            volumePercentageDisplay.textContent = `${this.value}%`; // 同步外部音量百分比

            if (volume === 0) {
                inVideoVolumeIcon.className = 'fas fa-volume-off';
            } else if (volume < 0.5) {
                inVideoVolumeIcon.className = 'fas fa-volume-down';
            } else {
                inVideoVolumeIcon.className = 'fas fa-volume-up';
            }
            updateMuteButtonIcon(); // 确保静音按钮图标也同步
        });

        inVideoVolumeIcon.addEventListener('click', toggleMute); // 点击图标静音/取消静音

        // 鼠标滚轮调节音量
        inVideoVolumeSlider.addEventListener('wheel', function(e) {
            e.preventDefault(); // 阻止页面滚动
            let currentVolume = parseInt(this.value);
            if (e.deltaY < 0) { // 向上滚动，增大音量
                currentVolume = Math.min(100, currentVolume + 5);
            } else { // 向下滚动，减小音量
                currentVolume = Math.max(0, currentVolume - 5);
            }
            this.value = currentVolume;
            this.dispatchEvent(new Event('input')); // 触发 input 事件来更新音量和UI
        });
    }


    /**
     * 设置字幕样式控制。
     */
    function setupSubtitleSettings() {
      subtitleSizeSlider.value = currentSubtitleSettings.fontSize;
      subtitleSizeValue.value = currentSubtitleSettings.fontSize;
      subtitleColorPicker.value = currentSubtitleSettings.color;
      applySubtitleSettings();

      subtitleSizeSlider.addEventListener('input', function () {
        subtitleSizeValue.value = this.value;
        currentSubtitleSettings.fontSize = parseInt(this.value);
        applySubtitleSettings();
        saveAllSettings();
      });

      subtitleSizeValue.addEventListener('change', function () {
        let val = parseInt(this.value);
        if (isNaN(val) || val < parseInt(subtitleSizeSlider.min) || val > parseInt(subtitleSizeSlider.max)) {
          val = defaultSubtitleSettings.fontSize;
          this.value = val;
        }
        subtitleSizeSlider.value = val;
        currentSubtitleSettings.fontSize = val;
        applySubtitleSettings();
        saveAllSettings();
      });

      subtitleColorPicker.addEventListener('input', function () {
        currentSubtitleSettings.color = this.value;
        applySubtitleSettings();
        saveAllSettings();
      });
    }

    /**
     * 应用字幕样式。
     */
    function applySubtitleSettings() {
      subtitleDisplay.style.fontSize = `${currentSubtitleSettings.fontSize}px`;
      subtitleDisplay.style.color = currentSubtitleSettings.color;
    }

    /**
     * 保存所有设置到 localStorage。
     */
    function saveAllSettings() {
      localStorage.setItem('subtitleSettings', JSON.stringify(currentSubtitleSettings));
      localStorage.setItem('transformSettings', JSON.stringify(transformSettings));
      localStorage.setItem('filterSettings', JSON.stringify(filterSettings));
      localStorage.setItem('playbackRate', videoPlayer.playbackRate || 1.0);
      localStorage.setItem('backgroundSettings', JSON.stringify(backgroundSettings));
      localStorage.setItem('loopMode', currentLoopMode); // 保存循环模式
    }

    /**
     * 从 localStorage 加载所有设置。
     */
    function loadAllSettings() {
      // 加载字幕设置
      const savedSubtitleSettings = localStorage.getItem('subtitleSettings');
      if (savedSubtitleSettings) {
        Object.assign(currentSubtitleSettings, JSON.parse(savedSubtitleSettings));
        setupSubtitleSettings();
      }

      // 加载画面变换设置
      const savedTransformSettings = localStorage.getItem('transformSettings');
      if (savedTransformSettings) {
        Object.assign(transformSettings, JSON.parse(savedTransformSettings));
        zoomSlider.value = transformSettings.zoom;
        zoomValueSpan.textContent = `${transformSettings.zoom}%`;
        applyVideoTransformations();
      }

      // 加载滤镜设置
      const savedFilterSettings = localStorage.getItem('filterSettings');
      if (savedFilterSettings) {
        Object.assign(filterSettings, JSON.parse(savedFilterSettings));
        updateFilterSlidersUI();
        applyVideoFilters();
        // 检查是否与预设匹配，并激活相应按钮
        let matchedPreset = false;
        for (const presetKey in filterPresets) {
          const p = filterPresets[presetKey];
          if (p.brightness === filterSettings.brightness &&
              p.contrast === filterSettings.contrast &&
              p.saturation === filterSettings.saturation &&
              p.sharpen === filterSettings.sharpen) {
            const presetButton = document.querySelector(`#filterPresetsContainer .preset-btn[data-preset="${presetKey}"]`);
            if (presetButton) presetButton.classList.add('active-preset');
            matchedPreset = true;
            break;
          }
        }
        if (!matchedPreset) clearActiveFilterPreset();
      }

      // 加载播放速度
      const savedPlaybackRate = localStorage.getItem('playbackRate');
      if (savedPlaybackRate) {
        changeSpeed(parseFloat(savedPlaybackRate), document.querySelector(`#speedBtnGroup .btn[data-speed="${savedPlaybackRate}"]`));
      } else {
        changeSpeed(1.0, document.querySelector(`#speedBtnGroup .btn[data-speed="1"]`));
      }

      // 加载背景设置
      const savedBackgroundSettings = localStorage.getItem('backgroundSettings');
      if (savedBackgroundSettings) {
        Object.assign(backgroundSettings, JSON.parse(savedBackgroundSettings));
      } else {
        // 如果没有保存的设置，则使用默认值
        Object.assign(backgroundSettings, defaultBackgroundSettings);
      }
      backgroundURLInput.value = backgroundSettings.url;
      backgroundBlurSlider.value = backgroundSettings.blur;
      backgroundBlurValueSpan.textContent = `${backgroundSettings.blur}px`;
      applyBackground();

      // 加载循环模式
      currentLoopMode = localStorage.getItem('loopMode') || 'none';
      updateLoopModeButtons();
    }

    /**
     * 更新播放状态。
     */
    function updateStatus(status, message) {
      const indicator = document.getElementById('statusIndicator');
      indicator.className = `status-indicator ${status}`;
      indicator.innerHTML = `<i class="fas fa-circle"></i> ${message}`;
    }

    /**
     * 切换播放/暂停状态。
     */
    function togglePlayPause() {
      if (videoPlayer.src) {
        if (videoPlayer.paused) {
          videoPlayer.play();
        } else {
          videoPlayer.pause();
        }
      } else {
        alert('请先加载视频！');
      }
    }

    /**
     * 重新加载视频。
     */
    function reloadVideo() {
        const inputUrl = document.getElementById('videoURL').value.trim();

        if (inputUrl.startsWith('本地文件:')) {
            if (currentLocalFileObject) {
                playLocalVideo(currentLocalFileObject);
                return;
            }
            alert('本地视频文件已丢失，请重新选择或上传。');
            document.getElementById('videoURL').value = '';
            stopPlaybackInternal(false);
        } else if (inputUrl) {
            play(inputUrl);
        } else {
            alert('请输入视频URL或点击“上传本地视频”按钮选择文件以重新加载。');
        }
    }

    /**
     * 播放本地视频。
     */
    function playLocalVideo(file) {
      const extension = file.name.split('.').pop().toLowerCase();

      if (!supportedFormats.includes(extension)) {
        alert(`不支持的视频格式: .${extension}\n请尝试其他视频文件，或确保文件未损坏。`);
        updateStatus('stopped', `不支持的格式: .${extension}`);
        return;
      }

      if (videoPlayer.src && videoPlayer.src.startsWith('blob:')) {
        URL.revokeObjectURL(videoPlayer.src);
      }

      currentLocalFileObject = file;
      currentLocalFileName = file.name;
      const fileURL = URL.createObjectURL(file);

      document.getElementById('videoURL').value = `本地文件: ${file.name}`;

      stopPlaybackInternal(true); // 停止当前播放，保持占位符隐藏

      currentVideoUrl = fileURL;
      play(fileURL, true); // 标记为本地文件播放

      // 添加到历史记录，并设置 currentPlayingHistoryIndex
      const historyItem = {
          title: `本地文件: ${file.name}`,
          url: fileURL,
          fileName: file.name,
          type: 'local',
          timestamp: new Date().toISOString(),
      };
      addToHistory(historyItem);
      // 当播放本地文件时，如果它被添加到历史记录的开头，则其索引为0
      currentPlayingHistoryIndex = 0;

      updateStatus('playing', `正在播放: ${file.name}`);
    }

    /**
     * 自动检测并播放视频。
     * @param {string} url - 视频地址
     * @param {boolean} isLocalPlayback - 是否为本地文件播放 (用于区分历史记录处理)
     */
    function play(url, isLocalPlayback = false) {
      stopPlaybackInternal(true); // 停止之前的播放并清理

      currentVideoUrl = url;

      updateStatus('loading', '正在加载视频...');

      uploadPlaceholder.classList.add('hidden');
      videoContainerElement.classList.add('visible');

      applyVideoTransformations();
      applyVideoFilters();

      if (url.startsWith('blob:')) {
        videoPlayer.src = url;
        videoPlayer.currentTime = 0.01;
        videoPlayer.play().catch((e) => {
          console.error('本地视频播放错误:', e);
          updateStatus('stopped', '播放错误: ' + e.message);
          uploadPlaceholder.classList.remove('hidden');
          videoContainerElement.classList.remove('visible');
        });
        return;
      }

      if (url.indexOf('rtmp://') === 0) {
        alert('当前浏览器不支持 RTMP 协议播放，请尝试其他视频格式！');
        updateStatus('stopped', '不支持RTMP协议');
        uploadPlaceholder.classList.remove('hidden');
        videoContainerElement.classList.remove('visible');
        return;
      }

      const extension = getFileExtension(url);

      if (extension === 'm3u8' || url.includes('.m3u8')) {
        if (Hls.isSupported()) {
          hlsInstance = new Hls();
          hlsInstance.loadSource(url);
          hlsInstance.attachMedia(videoPlayer);
          hlsInstance.on(Hls.Events.MANIFEST_PARSED, function () {
            videoPlayer.currentTime = 0.01;
            videoPlayer.play().catch((e) => {
              console.error('HLS播放错误:', e);
              updateStatus('stopped', '播放错误: ' + e.message);
              uploadPlaceholder.classList.remove('hidden');
              videoContainerElement.classList.remove('visible');
            });
          });
          hlsInstance.on(Hls.Events.ERROR, function (event, data) {
            console.error('HLS错误:', data);
            updateStatus('stopped', 'HLS错误: ' + data.details);
            uploadPlaceholder.classList.remove('hidden');
            videoContainerElement.classList.remove('visible');
          });
        } else if (videoPlayer.canPlayType('application/vnd.apple.mpegurl')) {
          videoPlayer.src = url;
          videoPlayer.currentTime = 0.01;
          videoPlayer.play().catch((e) => {
            console.error('原生HLS播放错误:', e);
            updateStatus('stopped', '播放错误: ' + e.message);
            uploadPlaceholder.classList.remove('hidden');
            videoContainerElement.classList.remove('visible');
          });
        } else {
          alert('当前浏览器不支持 HLS 视频播放！');
          updateStatus('stopped', '不支持HLS播放');
          uploadPlaceholder.classList.remove('hidden');
          videoContainerElement.classList.remove('visible');
          return;
        }
      }
      else if (extension === 'flv' || url.includes('.flv')) {
        if (flvjs.isSupported()) {
          flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url: url,
          });
          flvPlayer.attachMediaElement(videoPlayer);
          flvPlayer.load();
          videoPlayer.currentTime = 0.01;
          flvPlayer.play().catch((e) => {
            console.error('FLV播放错误:', e);
            updateStatus('stopped', '播放错误: ' + e.message);
            uploadPlaceholder.classList.remove('hidden');
            videoContainerElement.classList.remove('visible');
          });
        } else {
          alert('当前浏览器不支持 FLV 视频播放！');
          updateStatus('stopped', '不支持FLV播放');
          uploadPlaceholder.classList.remove('hidden');
          videoContainerElement.classList.remove('visible');
          return;
        }
      }
      else {
        // 对于普通视频文件，尝试直接播放
        videoPlayer.src = url;
        videoPlayer.currentTime = 0.01;
        videoPlayer.play().catch((e) => {
          console.error('原生播放错误:', e);
          updateStatus('stopped', '播放失败，尝试其他方式...');

          // 如果原生播放失败，尝试使用HLS回退
          if (Hls.isSupported()) {
            updateStatus('loading', '尝试使用HLS播放...');
            hlsInstance = new Hls();
            hlsInstance.loadSource(url);
            hlsInstance.attachMedia(videoPlayer);
            hlsInstance.on(Hls.Events.MANIFEST_PARSED, function () {
              videoPlayer.currentTime = 0.01;
              videoPlayer.play().catch((e) => {
                console.error('HLS回退播放错误:', e);
                updateStatus('stopped', '播放失败');
                uploadPlaceholder.classList.remove('hidden');
                videoContainerElement.classList.remove('visible');
              });
            });
            hlsInstance.on(Hls.Events.ERROR, function (event, data) {
              console.error('HLS回退错误:', data);
              updateStatus('stopped', 'HLS回退错误: ' + data.details);
              uploadPlaceholder.classList.remove('hidden');
              videoContainerElement.classList.remove('visible');
            });
          } else {
            updateStatus('stopped', '播放失败，浏览器不支持此格式。');
            uploadPlaceholder.classList.remove('hidden');
            videoContainerElement.classList.remove('visible');
          }
        });
      }
      // 添加到历史记录 (只有网络URL才添加到历史记录，本地视频已在 playLocalVideo 中添加)
      if (!isLocalPlayback && !url.startsWith('blob:')) {
        const historyItem = {
            title: url, // 默认使用URL作为标题
            url: url,
            fileName: null,
            type: 'remote',
            timestamp: new Date().toISOString(),
        };
        addToHistory(historyItem);
        // 当播放新网络视频时，它被添加到历史记录的开头，则其索引为0
        currentPlayingHistoryIndex = 0;
      }
    }

    /**
     * 停止播放内部实现。
     * @param {boolean} keepPlaceholderHidden - 是否保持占位符隐藏。
     */
    function stopPlaybackInternal(keepPlaceholderHidden = false) {
      videoPlayer.pause();
      if (videoPlayer.src && videoPlayer.src.startsWith('blob:')) {
        URL.revokeObjectURL(videoPlayer.src);
      }
      videoPlayer.removeAttribute('src');
      videoPlayer.load();

      videoPlayer.currentTime = 0;
      seekSlider.value = 0;
      inVideoSeekSlider.value = 0; // 同步视频内部进度条
      currentTimeDisplay.textContent = '00:00';
      inVideoCurrentTimeDisplay.textContent = '00:00'; // 同步视频内部时间
      durationDisplay.textContent = '00:00';
      inVideoDurationDisplay.textContent = '00:00'; // 同步视频内部总时长

      if (hlsInstance) {
        hlsInstance.destroy();
        hlsInstance = null;
      }
      if (flvPlayer) {
        flvPlayer.destroy();
        flvPlayer = null;
      }

      currentVideoUrl = null;
      currentPlayingHistoryIndex = -1; // 停止播放时重置历史索引

      removeSubtitle(); // 清理字幕

      updateStatus('stopped', '播放器已停止');

      if (!keepPlaceholderHidden) {
        uploadPlaceholder.classList.remove('hidden');
        videoContainerElement.classList.remove('visible');
        // 只有当不保持占位符隐藏时才清空输入框和本地文件信息
        document.getElementById('videoURL').value = '';
        currentLocalFileObject = null;
        currentLocalFileName = null;
      }

      playPauseIcon.className = 'fas fa-play';
      inVideoPlayPauseIcon.className = 'fas fa-play'; // 同步视频内部按钮
      clearTimeout(controlsHideTimeout); // 停止播放时，清除自动隐藏计时器
      inVideoControls.classList.add('controls-visible'); // 停止播放时，控制条保持显示
    }

    /**
     * 停止播放 (外部接口)。
     */
    function stopPlayback() {
      stopPlaybackInternal(false);
    }

    /**
     * 获取文件扩展名。
     */
    function getFileExtension(url) {
      const parts = url.split('.');
      if (parts.length > 1) {
        return parts.pop().split(/[#?]/)[0].toLowerCase();
      }
      return '';
    }

    /**
     * Helper: 将时间字符串 (HH:MM:SS,ms 或 HH:MM:SS.ms) 转换为秒数。
     */
    function parseTime(timeStr) {
      const parts = timeStr.split(':');
      const secondsAndMs = parts[parts.length - 1].split(/[,.]/);
      let hours = 0, minutes = 0, seconds = 0, milliseconds = 0;

      if (parts.length === 3) {
          hours = parseInt(parts[0], 10);
          minutes = parseInt(parts[1], 10);
          seconds = parseInt(secondsAndMs[0], 10);
          milliseconds = parseInt(secondsAndMs[1], 10) || 0;
      } else if (parts.length === 2) {
          minutes = parseInt(parts[0], 10);
          seconds = parseInt(secondsAndMs[0], 10);
          milliseconds = parseInt(secondsAndMs[1], 10) || 0;
      }
      return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000;
    }

    /**
     * 解析 SRT 或 VTT 内容为字幕对象数组。
     */
    function parseSrtOrVtt(content) {
      const subtitles = [];
      const lines = content.split(/\r?\n/);
      let i = 0;
      while (i < lines.length) {
        if (!lines[i].trim() || (isNaN(parseInt(lines[i].trim(), 10)) && !lines[i].trim().toUpperCase().startsWith('WEBVTT') && !lines[i].trim().startsWith('NOTE') && !lines[i].trim().startsWith('STYLE') && !lines[i].trim().includes('-->'))) {
          i++;
          continue;
        }

        if (lines[i].trim().toUpperCase() === 'WEBVTT') {
          i++;
          while (i < lines.length && lines[i].trim() === '') i++;
          continue;
        }
        if (lines[i].trim().startsWith('NOTE') || lines[i].trim().startsWith('STYLE')) {
          i++;
          while (i < lines.length && lines[i].trim() !== '') i++;
          while (i < lines.length && lines[i].trim() === '') i++;
          continue;
        }

        let cueId = '';
        if (!isNaN(parseInt(lines[i].trim(), 10))) {
          cueId = lines[i].trim();
          i++;
          while (i < lines.length && lines[i].trim() === '') i++;
        }

        let timeLine = '';
        if (i < lines.length && lines[i].includes('-->')) {
          timeLine = lines[i].trim();
          i++;
        } else {
          i++;
          continue;
        }

        let textLines = [];
        while (i < lines.length && lines[i].trim() !== '') {
          textLines.push(lines[i].trim());
          i++;
        }

        const timeParts = timeLine.split(' --> ');
        if (timeParts.length === 2) {
          const start = parseTime(timeParts[0]);
          const end = parseTime(timeParts[1]);
          const text = textLines.join('\n');
          subtitles.push({ start, end, text });
        }
      }
      return subtitles;
    }

    /**
     * 上传字幕文件并加载。
     */
    function uploadSubtitleFile() {
      const input = document.createElement('input');
      input.type = 'file';
      input.accept = '.vtt,.srt';
      input.style.display = 'none';

      input.onchange = function (e) {
        const file = e.target.files[0];
        if (!file) return;

        const reader = new FileReader();
        reader.onload = function (event) {
          const content = event.target.result;
          parseAndActivateSubtitle(content);
          currentSubtitleFileName = file.name;
          updateSubtitleSelectLabel(file.name);
        };
        reader.readAsText(file);
      };

      document.body.appendChild(input);
      input.click();
      document.body.removeChild(input);
    }

    /**
     * 更新字幕选择下拉显示文本（显示文件名，且禁用“上传字幕文件”选项）。
     */
    function updateSubtitleSelectLabel(fileName) {
      const subtitleSelect = document.getElementById('subtitleSelect');
      subtitleSelect.innerHTML = '';

      const noneOption = document.createElement('option');
      noneOption.value = 'none';
      noneOption.textContent = '无字幕';
      subtitleSelect.appendChild(noneOption);

      if (fileName) {
        const fileOption = document.createElement('option');
        fileOption.value = 'uploaded';
        fileOption.textContent = fileName;
        fileOption.selected = true;
        subtitleSelect.appendChild(fileOption);
      } else {
        noneOption.selected = true;
      }
    }

    /**
     * 解析并激活自定义字幕。
     */
    function parseAndActivateSubtitle(content) {
      currentSubtitleTracks = parseSrtOrVtt(content);
      subtitleActive = true;
      subtitleDisplay.style.display = 'block';
      subtitleDisplay.textContent = '';
      updateSubtitleDisplay(videoPlayer.currentTime);
      applySubtitleSettings();
      updateToggleSubtitleButtonIcon();
    }

    /**
     * 根据当前播放时间更新自定义字幕显示。
     */
    function updateSubtitleDisplay(currentTime) {
      let currentCaption = '';

      for (const track of currentSubtitleTracks) {
        if (currentTime >= track.start && currentTime <= track.end) {
          currentCaption = track.text;
          break;
        }
      }
      subtitleDisplay.innerHTML = currentCaption.replace(/\n/g, '<br>');
      subtitleDisplay.style.display = currentCaption ? 'block' : 'none';
    }

    /**
     * 切换字幕显示（仅针对自定义字幕）。
     */
    function toggleSubtitle() {
      if (currentSubtitleTracks.length === 0) {
        alert('没有加载外挂字幕文件。请先上传字幕文件。');
        subtitleActive = false;
        updateToggleSubtitleButtonIcon();
        subtitleDisplay.style.display = 'none';
        return;
      }

      subtitleActive = !subtitleActive;

      if (subtitleActive) {
        updateSubtitleDisplay(videoPlayer.currentTime);
        subtitleDisplay.style.display = 'block';
      } else {
        subtitleDisplay.style.display = 'none';
      }
      updateToggleSubtitleButtonIcon();
    }

    /**
     * 更新显示/隐藏字幕按钮的图标。
     */
    function updateToggleSubtitleButtonIcon() {
      const toggleBtn = document.getElementById('toggleSubtitleBtn');
      if (toggleBtn) {
        const toggleIcon = toggleBtn.querySelector('i');
        if (toggleIcon) {
          if (subtitleActive) {
            toggleIcon.className = 'fas fa-eye';
          } else {
            toggleIcon.className = 'fas fa-eye-slash';
          }
        }
      }
    }

    /**
     * 移除所有字幕（自定义）。
     */
    function removeSubtitle() {
      currentSubtitleTracks = [];
      subtitleActive = false;
      currentSubtitleFileName = null;
      subtitleDisplay.textContent = '';
      subtitleDisplay.style.display = 'none';

      for (let i = 0; i < videoPlayer.textTracks.length; i++) {
        videoPlayer.textTracks[i].mode = 'disabled';
      }

      updateSubtitleSelectLabel(null);
      updateToggleSubtitleButtonIcon();
    }

    /**
     * Function to determine if a URL is likely a valid video URL.
     */
    function isValidVideoUrl(url) {
      const videoExtensions = ['mp4', 'm3u8', 'flv', 'webm', 'mkv', 'mov', 'avi', 'wmv', '3gp', 'ogg', 'mpg', 'mpeg', 'vob', 'ts',];
      const extension = getFileExtension(url);

      if (url.startsWith('blob:')) {
        return true;
      }

      if (videoExtensions.includes(extension)) {
        return true;
      }

      if (url.includes('.m3u8') || url.includes('.flv')) {
        return true;
      }

      try {
        new URL(url);
        return false;
      } catch (e) {
        return false;
      }
    }

    /**
     * 添加到历史记录。
     * @param {object} newItem - 包含 title, url, fileName, type, timestamp 的对象。
     */
    function addToHistory(newItem) {
      // 检查是否已存在相同的项
      const existsIndex = playbackHistory.findIndex(item =>
        (item.type === 'local' && item.fileName === newItem.fileName) ||
        (item.type === 'remote' && item.url === newItem.url)
      );

      if (existsIndex !== -1) {
        // 如果存在，先移除旧的，再添加到最前面，保持最新播放的在顶部
        playbackHistory.splice(existsIndex, 1);
      }

      playbackHistory.unshift(newItem);

      if (playbackHistory.length > 20) { // 增加历史记录上限
          playbackHistory.pop();
      }

      localStorage.setItem('playbackHistory', JSON.stringify(playbackHistory));
      renderHistory();
    }

    /**
     * Helper function to create event handlers for input.
     */
    function createInputHandlers(index) {
      const historyItem = document.getElementById(`historyItem_${index}`);
      const editInput = historyItem.querySelector('.history-title-edit');

      const blurHandler = (event) => {
        if (currentlyEditingIndex === index) {
            if (!event.relatedTarget || !event.relatedTarget.closest('.edit-save-btn')) {
                saveEditMode(index);
            }
        }
      };

      const keypressHandler = (event) => {
        if (event.key === 'Enter') {
          saveEditMode(index);
          event.preventDefault();
        }
      };

      return { blurHandler, keypressHandler };
    }

    /**
     * 启动编辑模式。
     */
    function startEditMode(index) {
      if (currentlyEditingIndex !== -1 && currentlyEditingIndex !== index) {
        saveEditMode(currentlyEditingIndex);
      }

      const historyItem = document.getElementById(`historyItem_${index}`);
      if (!historyItem) return;

      const displaySpan = historyItem.querySelector('.history-title-display');
      const editInput = historyItem.querySelector('.history-title-edit');
      const editSaveBtn = historyItem.querySelector('.edit-save-btn');
      const editSaveIcon = editSaveBtn.querySelector('i');
      const editSaveLabel = editSaveBtn.querySelector('.button-label');


      displaySpan.style.display = 'none';
      editInput.style.display = 'inline-block';
      editInput.value = displaySpan.textContent;
      editInput.focus();
      editInput.select();

      editSaveBtn.setAttribute('data-action', 'save');
      editSaveIcon.className = 'fas fa-check';
      editSaveLabel.textContent = '保存';

      const handlers = createInputHandlers(index);
      editInput.addEventListener('blur', handlers.blurHandler);
      editInput.addEventListener('keypress', handlers.keypressHandler);
      // 使用 Map 存储监听器引用，以便正确移除
      if (!window._inputEventListenersMap) window._inputEventListenersMap = new Map();
      window._inputEventListenersMap.set(index, handlers);

      currentlyEditingIndex = index;
    }

    /**
     * 保存编辑模式。
     */
    function saveEditMode(index) {
      if (currentlyEditingIndex !== index) return;

      const historyItem = document.getElementById(`historyItem_${index}`);
      if (!historyItem) return;

      const displaySpan = historyItem.querySelector('.history-title-display');
      const editInput = historyItem.querySelector('.history-title-edit');
      const editSaveBtn = historyItem.querySelector('.edit-save-btn');
      const editSaveIcon = editSaveBtn.querySelector('i');
      const editSaveLabel = editSaveBtn.querySelector('.button-label');

      const newTitle = editInput.value.trim();

      if (newTitle === '') {
        editInput.value = playbackHistory[index].title;
      } else {
        playbackHistory[index].title = newTitle;
        localStorage.setItem('playbackHistory', JSON.stringify(playbackHistory));
      }
      displaySpan.textContent = playbackHistory[index].title;

      displaySpan.style.display = 'inline-block';
      editInput.style.display = 'none';

      editSaveBtn.setAttribute('data-action', 'edit');
      editSaveIcon.className = 'fas fa-edit';
      editSaveLabel.textContent = '备注';

      const handlers = window._inputEventListenersMap.get(index);
      if (handlers) {
        editInput.removeEventListener('blur', handlers.blurHandler);
        editInput.removeEventListener('keypress', handlers.keypressHandler);
        window._inputEventListenersMap.delete(index);
      }

      currentlyEditingIndex = -1;
    }

    /**
     * 渲染历史记录。
     */
    function renderHistory() {
      const historyList = document.getElementById('historyList');

      if (currentlyEditingIndex !== -1) {
        saveEditMode(currentlyEditingIndex);
      }

      if (window._inputEventListenersMap) {
        window._inputEventListenersMap.clear();
      }
      currentlyEditingIndex = -1;

      if (playbackHistory.length === 0) {
        historyList.innerHTML = '<div class="empty-history">暂无播放历史</div>';
        return;
      }

      historyList.innerHTML = '';

      playbackHistory.forEach((item, index) => {
        const historyItem = document.createElement('div');
        historyItem.className = 'history-item';
        historyItem.id = `historyItem_${index}`;

        let formatTagHtml = '';
        if (isValidVideoUrl(item.url)) {
          let format = '未知';
          if (item.type === 'local') {
            format = '本地';
          } else {
            const ext = getFileExtension(item.url);
            if (ext) {
              format = ext.toUpperCase();
            } else if (item.url.includes('.m3u8')) {
              format = 'M3U8';
            } else if (item.url.includes('.flv')) {
              format = 'FLV';
            }
          }
          formatTagHtml = `<div class="format-tag">${format}</div>`;
        }

        historyItem.innerHTML = `
          <div class="title-wrapper">
            <span class="history-title-display">${item.title}</span>
            <input type="text" class="history-title-edit" value="${item.title}" style="display:none;" />
          </div>
          ${formatTagHtml}
          <div class="actions">
            <button class="btn btn-icon" onclick="playFromHistory(${index})" aria-label="播放">
              <i class="fas fa-play"></i>
              <span class="button-label">播放</span>
            </button>
            <button class="btn btn-icon edit-save-btn" data-index="${index}" data-action="edit" aria-label="备注">
              <i class="fas fa-edit"></i>
              <span class="button-label">备注</span>
            </button>
            <button class="btn btn-icon" onclick="removeHistoryItem(${index})" aria-label="删除">
              <i class="fas fa-trash"></i>
              <span class="button-label">删除</span>
            </button>
          </div>
        `;
        historyList.appendChild(historyItem);
      });
    }

    /**
     * 从历史记录播放。
     */
    function playFromHistory(index) {
      const item = playbackHistory[index];
      if (!item) return;

      currentPlayingHistoryIndex = index; // 设置当前播放的历史记录索引

      if (item.type === 'local') {
        if (currentLocalFileObject && currentLocalFileName === item.fileName) {
            document.getElementById('videoURL').value = item.title; // 更新URL输入框显示
            play(item.url, true); // 播放本地文件
            return;
        }
        alert('本地视频文件已丢失，请重新上传。');
        document.getElementById('videoURL').value = '';
        stopPlaybackInternal(false);
      } else {
        document.getElementById('videoURL').value = item.url;
        play(item.url);
      }
    }

    /**
     * 删除历史记录项。
     */
    function removeHistoryItem(index) {
      playbackHistory.splice(index, 1);
      localStorage.setItem('playbackHistory', JSON.stringify(playbackHistory));
      renderHistory();
      // 如果删除的是当前正在播放的项，重置索引
      if (currentPlayingHistoryIndex === index) {
          currentPlayingHistoryIndex = -1;
      } else if (currentPlayingHistoryIndex > index) {
          currentPlayingHistoryIndex--; // 调整后续索引
      }
    }

    /**
     * 清空历史记录。
     */
    function clearHistory() {
      if (playbackHistory.length === 0) return;

      if (confirm('确定要清空所有播放历史吗？')) {
        playbackHistory = [];
        localStorage.removeItem('playbackHistory');
        renderHistory();
        currentPlayingHistoryIndex = -1; // 清空历史记录后重置索引
      }
    }

    /**
     * 切换全屏。
     */
    function toggleFullscreen() {
      if (!document.fullscreenElement) {
        if (videoContainerElement.requestFullscreen) {
          videoContainerElement.requestFullscreen();
        } else if (videoContainerElement.mozRequestFullScreen) {
          videoContainerElement.mozRequestFullScreen();
        } else if (videoContainerElement.webkitRequestFullscreen) {
          videoContainerElement.webkitRequestFullscreen();
        } else if (videoContainerElement.msRequestFullscreen) {
          videoContainerElement.msRequestFullscreen();
        }
      } else {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        } else if (document.msExitFullscreen) {
          document.msExitFullscreen();
        }
      }
    }

    /**
     * 更改播放速度。
     */
    function changeSpeed(speed, buttonElement) {
      videoPlayer.playbackRate = speed;
      document.querySelectorAll('#speedBtnGroup .btn').forEach(btn => btn.classList.remove('active-speed-btn'));
      if (buttonElement) {
        buttonElement.classList.add('active-speed-btn');
      }
      if (!videoPlayer.paused) {
        updateStatus('playing', `正在播放 (${speed}x)`);
      }
      saveAllSettings();
    }

    /**
     * 切换静音。
     */
    function toggleMute() {
      if (videoPlayer.volume > 0) {
        videoPlayer.dataset.previousVolume = videoPlayer.volume;
      }

      if (videoPlayer.volume > 0) {
        videoPlayer.volume = 0;
        volumeSlider.value = 0;
        inVideoVolumeSlider.value = 0;
      } else {
        const previousVolume = parseFloat(videoPlayer.dataset.previousVolume || 0.7);
        videoPlayer.volume = previousVolume;
        volumeSlider.value = Math.round(previousVolume * 100);
        inVideoVolumeSlider.value = Math.round(previousVolume * 100);
      }

      // 更新音量百分比显示
      volumePercentageDisplay.textContent = `${volumeSlider.value}%`;
      inVideoVolumePercentageDisplay.textContent = `${inVideoVolumeSlider.value}%`;

      if (videoPlayer.volume === 0) {
        volumeIcon.className = 'fas fa-volume-off';
        inVideoVolumeIcon.className = 'fas fa-volume-off';
      } else if (videoPlayer.volume < 0.5) {
        volumeIcon.className = 'fas fa-volume-down';
        inVideoVolumeIcon.className = 'fas fa-volume-down';
      } else {
        volumeIcon.className = 'fas fa-volume-up';
        inVideoVolumeIcon.className = 'fas fa-volume-up';
      }

      updateMuteButtonIcon();
    }

    /**
     * 更新静音按钮的图标。
     */
    function updateMuteButtonIcon() {
      const muteButton = document.getElementById('muteButton');
      if (muteButton && muteButtonIcon) {
        if (videoPlayer.volume === 0) {
          muteButtonIcon.className = 'fas fa-volume-off';
          muteButton.setAttribute('aria-label', '取消静音');
        } else {
          muteButtonIcon.className = 'fas fa-volume-up';
          muteButton.setAttribute('aria-label', '静音');
        }
      }
    }

    /**
     * 主题切换功能。
     */
    document.getElementById('themeToggle').addEventListener('click', function () {
      document.body.classList.toggle('dark-mode');
      localStorage.setItem('darkMode', document.body.classList.contains('dark-mode'));

      const icon = this.querySelector('i');
      if (document.body.classList.contains('dark-mode')) {
        icon.className = 'fas fa-sun';
      } else {
        icon.className = 'fas fa-moon';
      }
    });

    /**
     * 加载主题设置。
     */
    function loadTheme() {
      const darkMode = localStorage.getItem('darkMode') === 'true';
      const themeToggle = document.getElementById('themeToggle');
      const icon = themeToggle.querySelector('i');

      if (darkMode) {
        document.body.classList.add('dark-mode');
        icon.className = 'fas fa-sun';
      } else {
        icon.className = 'fas fa-moon';
      }
    }

    /**
     * 处理键盘事件 (空格键播放/暂停，左右方向键快进/快退)。
     */
    function handleKeyDown(event) {
        // 检查焦点是否在输入框或文本区域
        const isInputFocused = event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA';

        if (event.key === ' ' && !isInputFocused) {
            event.preventDefault(); // 阻止默认的空格键行为 (如页面滚动)
            togglePlayPause();
        } else if (event.key === 'ArrowLeft' && !isInputFocused) {
            event.preventDefault();
            videoPlayer.currentTime = Math.max(0, videoPlayer.currentTime - 5); // 快退 5 秒
        } else if (event.key === 'ArrowRight' && !isInputFocused) {
            event.preventDefault();
            videoPlayer.currentTime = Math.min(videoPlayer.duration, videoPlayer.currentTime + 5); // 快进 5 秒
        }
    }

    /**
     * 设置循环模式。
     * @param {string} mode - 'none', 'single', 'list', 'shuffle'
     */
    function setLoopMode(mode) {
        if (currentLoopMode === mode) {
            currentLoopMode = 'none'; // 再次点击取消
        } else {
            currentLoopMode = mode;
        }
        localStorage.setItem('loopMode', currentLoopMode);
        updateLoopModeButtons();

        // 提示用户当前循环模式
        let message = '';
        switch(currentLoopMode) {
            case 'single':
                message = '已开启单曲循环';
                break;
            case 'list':
                message = '已开启列表循环';
                break;
            case 'shuffle':
                message = '已开启随机播放';
                break;
            default:
                message = '已关闭循环模式';
                break;
        }
        updateStatus('stopped', message); // 使用停止状态的样式显示提示
    }

    /**
     * 更新循环模式按钮的激活状态。
     */
    function updateLoopModeButtons() {
        document.querySelectorAll('.history-loop-controls .btn').forEach(btn => {
            if (btn.dataset.loopMode === currentLoopMode) {
                btn.classList.add('active-loop-mode');
            } else {
                btn.classList.remove('active-loop-mode');
            }
        });
    }


    // --- 新的下载功能 (参考用户提供代码) ---
    async function downloadVideo() {
      const url = currentVideoUrl; // Get the currently playing video URL

      if (!url) {
        alert('没有正在播放的视频可以下载。');
        return;
      }

      // Handle local files
      if (url.startsWith('blob:')) {
        alert('当前正在播放的是本地视频，无需下载。');
        return;
      }

      updateStatus('loading', '正在准备下载...');

      try {
        const extension = getFileExtension(url);
        let filename = `video_${Date.now()}`; // Default filename

        // Try to derive a better filename from the URL
        try {
            const urlObj = new URL(url);
            const pathSegments = urlObj.pathname.split('/');
            const lastSegment = pathSegments[pathSegments.length - 1];
            if (lastSegment && lastSegment.includes('.')) {
                filename = lastSegment.split('?')[0].split('#')[0];
            } else if (extension) {
                filename += `.${extension}`;
            }
        } catch (e) {
            console.warn("Could not parse URL for filename, using default.", e);
            if (extension) {
                filename += `.${extension}`;
            }
        }

        if (extension === 'm3u8' || url.includes('.m3u8')) {
          // HLS (M3U8) download
          await downloadHLS(url, filename);
        } else if (extension === 'flv' || url.includes('.flv')) {
          // FLV download (assuming direct FLV file)
          // For FLV, if it's a direct file, a simple download works.
          // If it's a stream, it's more complex, but for VOD FLV, direct download is often possible.
          await downloadDirect(url, filename);
        } else {
          // Direct download for other formats (MP4, WebM etc.)
          await downloadDirect(url, filename);
        }
        updateStatus('playing', '下载准备完成，浏览器将开始下载。');
      } catch (error) {
        console.error('下载失败:', error);
        updateStatus('stopped', `下载失败: ${error.message || '未知错误'}`);
        alert(`下载失败: ${error.message || '未知错误'}\n请检查控制台获取更多信息。`);
      }
    }

    // Helper for direct file download
    async function downloadDirect(url, filename) {
      const a = document.createElement('a');
      a.href = url;
      a.download = filename; // Suggest a filename
      document.body.appendChild(a);
      a.click();
      // Give browser a moment to initiate download before revoking
      setTimeout(() => {
          document.body.removeChild(a);
          // If it's a blob URL, revoke it (though for direct URL, browser manages)
          if (url.startsWith('blob:')) {
              URL.revokeObjectURL(url);
          }
      }, 100);
    }

    // Helper for HLS (M3U8) download
    async function downloadHLS(m3u8Url, baseFilename) {
      updateStatus('loading', '正在下载M3U8播放列表...');
      const response = await fetch(m3u8Url);
      if (!response.ok) {
        throw new Error(`Failed to fetch M3U8 manifest: ${response.statusText}`);
      }
      const manifestText = await response.text();

      const segmentUrls = [];
      const baseUrl = m3u8Url.substring(0, m3u8Url.lastIndexOf('/') + 1); // Correct baseUrl calculation

      const lines = manifestText.split('\n'); // Split manifest into lines
      for (const line of lines) {
        if (line.startsWith('#') || line.trim() === '') {
          continue; // Skip comments and empty lines
        }
        // Handle master playlist (if it points to other .m3u8 files)
        if (line.endsWith('.m3u8')) {
            const variantUrl = new URL(line, baseUrl).href; // Resolve relative URL
            console.log(`Found variant M3U8: ${variantUrl}. Attempting to download it.`);
            // Recursively call for the variant. This will download the first variant found.
            return downloadHLS(variantUrl, baseFilename);
        }
        // Assume it's a segment URL
        const segmentUrl = new URL(line, baseUrl).href; // Resolve relative URL
        segmentUrls.push(segmentUrl);
      }

      if (segmentUrls.length === 0) {
        throw new Error('No video segments found in the M3u8 manifest.');
      }

      const segmentData = [];
      let downloadedBytes = 0;
      let totalSegments = segmentUrls.length;

      for (let i = 0; i < totalSegments; i++) {
        const segmentUrl = segmentUrls[i];
        updateStatus('loading', `正在下载片段 ${i + 1}/${totalSegments}...`);
        const segmentResponse = await fetch(segmentUrl);
        if (!segmentResponse.ok) {
          throw new Error(`Failed to fetch segment ${i + 1}: ${segmentResponse.statusText}`);
        }
        const buffer = await segmentResponse.arrayBuffer();
        segmentData.push(new Uint8Array(buffer));
        downloadedBytes += buffer.byteLength;
      }

      updateStatus('loading', '正在合并视频片段...');
      // Concatenate all ArrayBuffers
      const totalLength = segmentData.reduce((acc, val) => acc + val.length, 0);
      const concatenatedBuffer = new Uint8Array(totalLength);
      let offset = 0;
      for (const segment of segmentData) {
        concatenatedBuffer.set(segment, offset);
        offset += segment.length;
      }

      // Determine MIME type. For .ts segments, it's typically video/mp2t.
      const blob = new Blob([concatenatedBuffer], { type: 'video/mp2t' });

      const downloadLink = document.createElement('a');
      downloadLink.href = URL.createObjectURL(blob);
      // Suggest .ts extension for concatenated HLS, remove .m3u8 from original filename
      downloadLink.download = `${baseFilename.replace(/\.m3u8$/, '')}.ts`;
      document.body.appendChild(downloadLink);
      downloadLink.click();
      setTimeout(() => {
          document.body.removeChild(downloadLink);
          URL.revokeObjectURL(downloadLink.href); // Clean up the object URL
      }, 100); // Delay revocation to ensure download starts
    }
  </script>
</body>
</html>